5

我目前正在学习著名的 C 书 - The C Programming Language, 2Ed。当我尝试 P.29 中的代码时,我认为 getline 函数有问题:

int getline(char s[], int lim) {
    int c, i;

    for (i=0; i<lim-1 && (c=getchar()) != EOF && c!='\n'; i++)
        s[i] = c;
    if (c == '\n') {
        s[i] = c;
        i++;
    }

    s[i] = '\0';
    return i;
}

如果当 for 循环结束时,i == lim-1并且c == '\n'?在这种情况下,我认为数组将超出边界,因为s[lim]将设置为“\ 0”。

有人认为这是错误的吗?谢谢你的帮助。

4

5 回答 5

4

运算符具有“&&早出”语义。这意味着 if i == lim-1,其余的条件不会被执行——特别是c = getchar()不会被调用。

这意味着在这种情况下,c它将从循环的最后一次迭代中获得它的值——并且由于循环条件包括c != '\n',所以这个值不能是'\n'(或者循环上次已经退出)。

只要lim大于 1 就为真,这必须是函数的先决条件(因为调用lim小于或等于 1 的函数会导致c读取未初始化的值)。

于 2013-06-27T02:33:28.420 回答
2

那么,让我们看一些案例:

如果lim == 0:,那么这将执行未定义的行为。有两个地方会发生这种情况:

  • 我们将不执行 for 循环的迭代,给出i == 0c == undefined
  • 然后我们访问c. (c == '\n')它还没有定义的值,所以它是未定义的行为。
  • 然后我们通过溢出再次导致未定义的行为ss[i] = '\0';

如果lim == 1

  • for 循环不会运行,因为条件不满足。
  • 我们将像 in 一样遇到未定义的行为,lim == 0因为c没有价值。
  • 最后一行将正常工作。

如果lim == 2, 输入字符串是"ab":

  • for 循环将抓取'a',并将其放入s.
  • for 循环将在下一次迭代中退出,其值c仍为'a'
  • if 条件失败。
  • 添加空字符可以正常工作。
  • 所以s == "a\0"

如果lim == 2输入字符串是什么"a\n"情况(您担心的是这种情况):

  • for 循环将抓取'a',并将其放入s.
  • for 循环将在下一次迭代中退出,其值c仍为'a'
  • if 条件失败。
  • 添加空字符可以正常工作。
  • 所以s == "a\0"
于 2013-06-27T02:37:10.877 回答
0

我认为你是对的。- 但以不同的方式。可能有问题。如果达到限制i==lim-1,并且 c 具有\n前一个循环的值 - 但这不可能发生,因为前一个循环c!='\n'会退出。

一个问题lim <=1。for 循环退出,c尚未初始化,因此未定义行为if (c == '\n')。可以用

int c = 0;

正如其他人所提到的,还有一个额外的lim = 0问题s[i] = '\0';

于 2013-06-27T02:37:57.793 回答
0

i存在lim-1c存在是不可能的'\n'。如果i==lim-1, theni<lim-1将是假的,所以它永远不会读取下一个字符。如果c'\n',那么循环将在igot to be之前终止lim-1

循环等效于:

i=0;
while (i<lim-1) {
    c = getchar();
    if (c==EOF) break;
    if (c=='\n') break;
    s[i] = c;
    i++;
}
于 2013-06-27T02:30:35.760 回答
0

循环将继续,直到条件 i < lim-1为真i == lim - 1。当循环条件为假时,循环将终止,数组的最后一个元素将存储在。s[lim -2]它不会超出边界。

于 2013-06-27T02:37:07.433 回答