在代码的一部分中包含/不包含++ i。 K& R最长线示例

时间:2013-04-22 03:36:44

标签: c

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;
}

这个例子来自K&amp; R book on C,第1.9章关于数组。我不明白为什么我们必须在++i声明中包含if?在外面写它应该做同样的工作。

    if(c=='\n')
        s[i] = c;
    ++i;
    s[i] = '\0'
return 0;
}

如果按照预期包含i程序,但在第二种情况下(我认为应该做同样的工作,这就是我编辑那部分的原因)它没有。我通过调试器运行它并观察i,在这两种情况下都正确计算并返回。但如果不接受++i,程序仍然无效。我没有从printf语句中获取我的打印,而Ctrl + D只是在终端或XTerm中无法工作(彻底的CodeBlocks)我无法弄清楚原因。有什么提示吗?我错过了一些合乎逻辑的步骤吗这是一个完整的代码:

//Program that reads lines and prints the longest
/*----------------------------------------------------------------------------*/

#include <stdio.h>
#define MAXLINE 1000

int getline(char currentline[], int maxlinelenght);
void copy(char saveto[], char copyfrom[]);
/*----------------------------------------------------------------------------*/

int main(void)
{
    int len, max;
    char line[MAXLINE], longest[MAXLINE];

    max = 0;
    while( (len = getline(line, MAXLINE)) > 0 )
        if(len > max){
            max = len;
            copy(longest, line);
        }
    if(max > 0)
        printf("StrLength:%d\nString:%s", max, longest);

return 0;
}
/*----------------------------------------------------------------------------*/

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;
}
/*----------------------------------------------------------------------------*/

void copy(char to[], char from[])
{
    int i;

    i = 0;
    while( (to[i]=from[i]) != '\0')
        ++i;
}
/*----------------------------------------------------------------------------*/

5 个答案:

答案 0 :(得分:2)

线路
if(c == '\n') 相当于
if(c != EOF)

这有助于解释为什么会发生拥抱吗?

答案 1 :(得分:1)

++i位于if语句中,因为如果我们不将i字符放在当前索引中,我们不想增加\n;这将导致在输入的最后一个字符和字符串末尾的\0之间留下一个索引。

答案 2 :(得分:1)

那里有一个逻辑:

if(c=='\n'){
    s[i] = c;
    ++i;
}

这意味着只有当您阅读其他换行符时,才需要再增加i一个,以便为\0字符留出空间。如果您将++i放在if块之外。这意味着即使没有i,也会1总是增加newline input,在这种情况下,因为i已经for loop增加了\0已经是++i的空间,因此,i将再次出错。您可以打印{{1}}的值并查看其工作原理。

答案 3 :(得分:1)

i指定的索引是当该行没有更多输入时应该放置终止空值的位置。索引i之前的位置包含字符串中的最后一个有效字符。

请记住,从stdin读取数据的循环可能会因读取\n字符以外的原因而终止。

如果你有这个结构:

if(c=='\n')
    s[i] = c;
++i;

然后,如果从stdin读取的最后一个字符不是换行符,则将索引递增一,而不将任何内容写入由预递增值i指定的位置。您可以有效地在结果中添加未指定的字符。

更糟(?),如果for循环由于i<lim-1条件而终止,则最终会在指定的数组末尾之后写入终止空字符,从而导致未定义的行为(内存损坏) )。

答案 4 :(得分:0)

由于3个条件,for循环可以退出 1.读取字符限制达到或EOF遇到 2.遇到新线

对于第一种情况我们需要将Null存储到字符串s中,因为我指向下一个有效字符读取的位置,所以不需要增加i。 但是对于第二种情况,当我指向下一个有效字符读取的位置时,我们现在将换行存储在该位置,然后递增i以存储NULL字符。

这就是为什么我们需要在第二种情况下增加i而不是第一种情况。

 if(c=='\n'){
            s[i] = c;
            ++i;
        }