`getchar()`会输出与输入字符串相同的内容。

51

我对 K&R 中提到使用 getchar() 的程序感到困惑。它输出的结果与输入字符串相同:

#include <stdio.h>

main(){
    int c;
    c = getchar();
    while(c != EOF){
         putchar(c);
         c = getchar();
    }
}
为什么它打印整个字符串?我本以为它会读取一个字符并再次要求输入。
另外,我们输入的所有字符串是否都以EOF结尾?

EOF不是char类型的值而是int类型的吗? - user379888
6
我认为它是一个值为-1的整数。 - Shubham
2
字符串以 \0 结尾。文件以 EOF 结尾,其值为 -1。 - user379888
3
我打开了一个文本文件,但是没有看到文件结尾处的EOF标记。 :) 无论如何,如果有需要,可以想出一种实现C语言的方法,其中EOF被定义为-42。在值方面如何定义EOF并不重要,你应该始终使用这个常量。 - Timothy
8
@Fahad:文件会在自己的结尾处自然结束,而不是在特定位置存在特定值时结束。EOF 的值取决于实现方式(通常为 -1;但始终为 EOF)。 - pmg
除此之外,我最近发现的是,由于putchar()在每个字符后面没有添加换行符,所以它会打印整个字符串。类似地,当您使用多个printf()而没有使用'\n'时,所有内容都会在同一行中显示。我们认为它只是一次性读取了整行,因此打印了整行,但实际上并非如此。 - Bryan Hernandez
5个回答

42

在你可能使用的简单设置中,getchar缓冲输入一起工作,所以你必须在 getchar 获得任何内容之前按回车键。字符串不是由 EOF 终止的;事实上,EOF 不是一个字符,而是表示文件结束的魔术值。但是 EOF 不是读取的字符串的一部分。当没有剩余内容可以读取时,它是 getchar 返回的值。


2
当我在K&R中尝试了计算字符的程序时,我发现get char()会像“abc”一样获取我的输入,但在计数时,它将是4而不是3。 因此,我使用gdb进行调试,结果发现附加的一个'字符'是(nl),其ascii码为0x0a。那么,我的输入是字符串吗?难道字符串不是以'\0'结尾的吗?为什么会有(nl)呢? - ray6080
1
这是因为终止该行的换行符是输入的一部分。C 就是这样,要处理它。 - Erich Kitzmueller

32

getchar()和相关函数从一个底层的缓冲区/流中读取数据。当你输入文本时,文本将存储在某个缓冲区中,getchar()可以逐个字符地读取它。每次读取都返回下一个字符,直到达到缓冲区的末尾。它不询问后续字符的原因是它可以从缓冲区获取下一个字符。

如果您运行脚本并直接在其中输入,它将继续提示您输入,直到您按下CTRL+D(文件结束)。如果您像这样调用它:./program < myInput,其中myInput是带有一些数据的文本文件,当getchar()读取到输入的末尾时,它会获取EOFEOF不是存在于流中的字符,而是一个哨兵值,表示已到达输入的结尾。

额外注意,如果getchar()遇到错误,它也将返回EOF,因此您应该检查ferror()。以下是示例(未经过测试,但您可以理解思路)。

main() {
    int c;
    do {
        c = getchar();
        if (c == EOF && ferror()) {
            perror("getchar");
        }
        else {
            putchar(c);
        }
    }
    while(c != EOF);
}

3
谢谢您提供CTRL+D的信息。 - estrar
1
“bash” 是创建缓冲区还是 Linux?看起来很奇怪,K&R 没有提到这个问题,尤其是他们基于 Unix。谢谢。 - Ron

11

按照 C 定义,字符串以 '\0' 结尾。程序中不存在 "C 字符串"

你的程序从标准输入(键盘)读取字符(缓冲直到按下 ENTER 键),并将它们写回标准输出(屏幕)。不管你输入多少字符或者持续多长时间,它都会这样做。

要停止程序,你需要表明标准输入没有更多数据 (啥?键盘怎么可能没有更多数据呢?)

你只需按下 Ctrl+D(Unix)或 Ctrl+Z(Windows)模拟文件已经到达结尾。
C 语言中,Ctrl+D(或 Ctrl+Z)并不是真正的字符。

如果你使用输入重定向运行程序,则 EOF 是实际的文件结尾,而不是虚构的结尾
./a.out < source.c


3

getchar() 函数读取一个输入字符并将该字符作为函数的值返回。如果读取字符时出现错误或到达了输入的结尾,getchar() 将返回一个特殊的值,用 EOF 表示。


2
根据getchar()的定义,它从标准输入中读取一个字符。不幸的是,stdin被误认为是键盘,这可能并非getchar的情况。getchar使用缓冲区作为stdin,逐个读取单个字符。在您的情况下,由于没有EOFgetcharputchar会运行多次,并且看起来整个字符串一次性打印出来。做一个小改变,您就会明白:
putchar(c);
printf("\n");     
c = getchar();

现在看一下输出结果与原始代码的比较。

另一个例子可以帮助您理解getchar和缓冲的stdin的概念:

void main(){
int c;
printf("Enter character");
c = getchar();
putchar();
c = getchar();
putchar();
}

在第一次输入时,输入两个字符。当 getchar 运行时,第二次输入时你输入了任何字符吗?没有,但是 putchar 仍然可以工作。
这最终意味着存在一个缓冲区,每当你输入一些内容并点击回车时,它就会进入缓冲区。 getchar 将此缓冲区用作 stdin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接