使用 getchar 读取一系列字符的正确方法是什么?

What is the correct way to read a series of characters using getchar?

我有两个源代码示例。我一直使用第一个示例,但奇怪的是我在数组的开头找到了字符“0”(第二个示例不会发生)。为什么第一个示例将字符 '0' 放在数组的开头?

示例 1:

/*
    Enter a sentence: ciao
    0 -> [=10=]
    1 -> c
    2 -> i
    3 -> a
    4 -> o
    5 -> [=10=]
*/

#include <stdio.h>
#define MAX 6

int main(void) {
    int i = 0;
    char ch, last_char, sentence[MAX] = { };

    printf("Enter a sentence: ");

    while ((ch = getchar()) != '\n' && i++ < MAX) {
        sentence[i] = ch;
    }

    for(i = 0; i < MAX; ++i) {
        if(sentence[i] == '[=10=]')
            printf("%d -> \0\n", i);
        else
            printf("%d -> %c\n", i, sentence[i]);
    }
    return 0;
}

示例 2:

/*
    Enter a sentence: ciao
    0 -> c
    1 -> i
    2 -> a
    3 -> o
    4 -> [=11=]
    5 -> [=11=]
*/

#include <stdio.h>
#define MAX 6

int main(void) {
    int i = 0;
    char ch, last_char, sentence[MAX] = { };

    printf("Enter a sentence: ");

    while ((ch = getchar()) != '\n') {
        sentence[i] = ch;
        if(i++ >= MAX - 1) break;   
    }

    for(i = 0; i < MAX; ++i) {
        if(sentence[i] == '[=11=]')
            printf("%d -> \0\n", i);
        else
            printf("%d -> %c\n", i, sentence[i]);
    }
    return 0;
}
while ((ch = getchar()) != '\n' && i++ < MAX) {
    sentence[i] = ch;
}

i=0开始。我们看读入的字符是不是换行符,如果是,我们看i是否小于MAX。之后,i 递增(现在是 1)。如果比较为真,我们将 sentence[i](与 sentence[1] 相同)设置为 ch。所以第一个位置 sentence[0] 永远不会分配给。这是错误。

在第二个示例中,您有一个 for 循环,这是正确的,因为 i 的递增发生在最后。

那是因为你在 while 条件下做 i++。所以它在 i 之前递增 你将它用作作业中的索引。您可以在不增加索引的情况下测试索引,并在分配中进行自动增加。

    while ((ch = getchar()) != '\n' && i < MAX) {
        sentence[i++] = ch;
    }

您实际上应该更改 && 操作数的顺序。如果您已经到达数组的末尾并且无法分配它,那么读取一个字符就没有意义了。

    while (i < MAX && (ch = getchar()) != '\n') {
        sentence[i++] = ch;
    }

有很多"correct"解决方案; "best" 是一个见仁见智的问题,但是您的第一个解决方案在语义上是不正确的,第二个解决方案不必要地不优雅。

第一个可以通过将 i 初始化为 -1 来 "corrected",但这不是惯用的。此外,您的建议都不会检查 EOF,这可能在例如从文件重定向输入或使用特定于平台的 CTRL 组合键时发生。

以下将索引变量本地化并检查 EOF:

for( int i = 0;
     i < MAX &&                   // Will fit in buffer AND 
     (ch = getchar()) != '\n' &&  // is not newline AND
     ch != EOF;                   // is not end-of-file
     i++ ;
{
    sentence[i] = ch ;
}         

这是有道理的,因为它完全反映了您的 output 循环。本地化 if i 可防止因在此代码中将 i 用于不同目的而可能发生的维护问题。您应该类似地本地化输出索引。

您的两个实现都没有为空终止符保留 space,这可能是故意的,但除此之外,要么:

char sentence[MAX + 1] ;

的限制子表达式 i < MAX - 1,或更好的 i < sizeof(sentence) - 1 - 后者防止对 sentence 的声明的更改可能使用 MAX 以外的其他内容未来的维护或再利用。