K& R中的函数示例返回错误的字符串长度?

时间:2014-08-23 21:16:33

标签: c arrays string

这是来自K& R的第65页。说明该函数返回字符串长度。这是代码:

int trim (char s[])
{
    int n;

    for (n = strlen(s)-1; n >= 0; n--)
        if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n')
            break;
    s[n+1] = '\0';
    return n;
}

看起来它应该返回n + 1。空字符不被视为字符串的一部分吗?

示例:

char s[4];
s[0] = c, s[1] = a, s[2] = t, s[3] = '\0';

这不意味着字符串大小为3并且有3个可用元素吗?该函数将返回2,这是不正确的。

另外,字符串长度定义为什么?

5 个答案:

答案 0 :(得分:3)

你绝对正确:退回的" n"在你的例子中==" strlen(s)-1&#34 ;; " strlen(s)"。

#include <stdio.h>
#include <string.h>

int 
trim (char s[])
{
  int initial_strlen = strlen(s);
  int n;

  for (n = initial_strlen-1; n >= 0; n--) {
    if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n')
      break;
  }
  s[n+1] = '\0';
  printf ("s=%s, initial strlen=%d, current strlen=%d, n=%d\n",
    s, initial_strlen, strlen(s), n);
  return n+1;
}

int 
main (int argc, char *argv[]) 
{
  char buf[80];

  strcpy(buf, "cat   ");
  printf ("trim #1= %d\n", trim (buf));

  strcpy(buf, "cat\t\t\t   ");
  printf ("trim #2= %d\n", trim (buf));
  return 0;
}

示例输出:

s=cat, initial strlen=6, current strlen=3, n=2
trim #1= 3
s=cat, initial strlen=9, current strlen=3, n=2
trim #2= 3

答案 1 :(得分:3)

问题在于它只是一个糟糕的代码。它是不应该编写代码的一个例子。通常,任何错误代码都包含错误,此示例演示了此规则。:) 这是一个糟糕的代码,因为至少你甚至无法自信地说出函数必须返回的内容。:)如果它不返回strlen(s)那么为什么它必须返回strlen(s) - 1特别是为空字符串。

我会按照以下方式编写函数

size_t trim( char s[] )
{
   size_t n = strlen( s );

   while ( n != 0 && ( s[n-1] == ' ' || s[n-1] == '\t' || s[n-1] == '\n' ) ) --n;

   s[n] = '\0';

   return n;
}

将我的代码与您展示的代码进行比较。在我的代码中很明显,如果循环不会被迭代,函数将返回strlen( s )。那就是你甚至不需要研究循环的作用。如果您删除循环,例如

size_t trim( char s[] )
{
   size_t n = strlen( s );

   s[n] = '\0';

   return n;
}

代码将非常清晰易读。它是一个不变的。

至于循环,它使用C ++中的双向迭代器的习惯用法。所以这样的代码再次易于阅读。并且没有任何中断声明。:)

考虑到删除tralling white space后函数返回sizeof( s )很重要。例如,当你想要连接两个字符串时可以使用它。

答案 2 :(得分:3)

你是正确的trim的给定实现不会返回结果字符串的长度。

不一定不正确

我的K&amp; R(第二版)副本说:

  

以下函数trim从字符串末尾删除尾随空格,制表符和换行符,使用break从最右边的非空白非选项卡退出循环,找到非换行符。

/* trim:  remove trailing blanks, tabs, newlines */
[... code ...]
     

strlen 会返回字符串的长度....

它没有说明trim的预期回报值是什么意思。虽然我同意它的实际返回值是不直观的,但它并不一定是错的,因为我们没有被告知它应该如何表现。

此外,您可能希望查看the errata for K&R's The C Programming Language(此示例未列出)。

答案 3 :(得分:1)

一方面,终止零字符不计入字符串 length 的一部分。这是strlen的工作原理,例如。例如。字符串"ABCD"的长度为4,这是很自然的事情。

另一方面,上面的trim函数确实返回的值少于实际的字符串长度。实际上,它应该返回n + 1

示例中的字符串长度确实为3。这是正确的长度。终止零字符计算为长度的一部分。如果计算终止零,则长度为4

答案 4 :(得分:1)

我想这本书中有一个错误,该函数应该是:

int trim(char s[])
{
    int n;
    for (n = strlen(s); n > 0; n--) {
        if (s[n-1] != ' ' && s[n-1] != '\t' && s[n-1] != '\n') {
            break;
        }
    }
    s[n] = '\0';
    return n;
}