在经典书籍“C编程语言”的第1.9章中的示例代码中是否有错误?

时间:2014-08-08 17:55:26

标签: c overflow kernighan-and-ritchie

在关于C语言的经典书籍的第1.9章" C编程语言"布莱恩&丹尼斯,有一个关于功能' getline'的代码。用于将下一行输入文本复制到char类型字符串并检查溢出。我引用下面的代码:

int getline(char line[], int maxline);
int getline(char s[], int limit)
{
    int c,i;
    for (i=0; i<limit-1 && (c=getchar())!=EOF && c!='\n'; ++i) /* ** */
        s[i]=c;
    if (c == '\n') {
        s[i]=c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

问题在于:参数&#39;限制&#39;是行的最大长度,因此数组s []只能包含从s [0]到s [limit-1]的元素集合。如果变量c到getchar()的最后一个字符是&#39; \ n&#39;并且这个字符的索引是limit-1,然后判断部分是&#39; for&#39;循环将失败,因为&#39; i == limit-1&#39;但不是&#39; c!=&#39; \ n&#39; (根据从左到右的顺序)。接下来,if子句将起作用,因为&#39; c ==&#39; \ n&#39;&#39;,然后s [limit-1] = c,那么++ i将设置i的值进入极限。 S [I] =&#39; \ 0&#39;会溢出,因为s [limit]超出了字符串的限制。我的分析是否合适?感谢您提供任何有用的答案。

2 个答案:

答案 0 :(得分:4)

你的分析是错误的。如果i == limit-1,由于短路评估,循环会在不读入c的情况下中断。所以,你永远不要输入if (c == '\n')i仍然是limit-1,并且没有溢出。

从概念上讲,你可以想到这样的循环条件:“如果i低于limit-1,则读取一个字符,如果它不是EOF或换行符,则输入循环体。”因此,如果ilimit-1,则您永远不会阅读。

答案 1 :(得分:3)

此代码中有两个短路的评估点。见下文

for (i=0; i<limit-1 && (c=getchar())!=EOF && c!='\n'; ++i)
//        (   A   )    (        B        )   (  C  )

全部用&&链分开。执行此代码时,所有三个必须为true或循环将中断。但是在短路评估中会发生以下情况:

  • 如果 A 为false,则条件为false, B和C都不会被评估。
  • 否则如果 B 为false,则条件为false且不评估C.
  • 否则,如果 C 为false,则条件为false。

...因此

  • 如果i<limit-1为false,既不 getchar(),也不会与EOF进行比较,也不会与'\n'进行比较。
  • 如果(c=getchar())!=EOF为false,则不执行与'\n'的比较。
  • 否则执行与'\n'的比较。

我希望这是有道理的。