Ctrl-D无法停止while(getchar()!=EOF)循环。

9
这是我的代码。我在Ubuntu终端中运行它。当我在终端中键入(a CtrlD)时,程序没有停止,而是继续等待我的输入。
在Unix中,CtrlD不等于EOF吗?
谢谢。
#include<stdio.h>

main() {
    int d;
    while(d=getchar()!=EOF) {
        printf("\"getchar()!=EOF\" result is %d\n", d);
        printf("EOF:%d\n", EOF);
    }
        printf("\"getchar()!=EOF\" result is %d\n", d);
}

1
那不是递归。它只是一个无限循环,直到您输入结束符号为止。递归=函数直接调用自身或在一些其他中间步骤之后调用自身。 - Marc B
我使用gcc编译了它,按下^D停止了循环。 - Jon Lin
@JonLin,只需输入^D即可。这对我也有效。但是,当输入为(a^D)时,循环没有停止。 - Sam
@MarcB 我犯了一个愚蠢的错误。谢谢你的帮助。 - Sam
2个回答

12

EOF不是一个字符。 EOF 是一个宏,当 getchar() 到达输入的末尾或遇到某种错误时,会返回这个宏。 ^D 不是“ EOF 字符”。在 Linux 下,当你在一个单独的行上按下 ^D 时,会关闭流,getchar() 调用到达输入的末尾并返回 EOF 宏。如果你在一行的中间键入 ^D,则流不会关闭,因此 getchar() 返回它读取的值,你的循环不会退出。

有关更好的描述,请参见 C faq 的 stdio 部分

此外:

在现代系统上,它不反映存储在文件中的任何实际结束符;它是没有更多字符可用的信号。


1
我仔细阅读了网站。在我看来,如果我在一行的中间输入 ^D,bash 将处理 ^D。因此,C 程序没有得到关闭流的命令。如果我在单独的一行中输入 ^D,C 程序将得到正确的命令。我的理解正确吗? - Sam
2
@qingfeng 这里有更多关于 ^D 的信息:http://www.c-faq.com/stdio/eofval.html 但是,除非它在单独的一行上,否则流不会被关闭。这里有一个简短的解释:https://dev59.com/ZnI_5IYBdhLWcg3wHvU5#1516177 - Jon Lin
8
当终端处于规范模式时,直到您按下回车键,行才不会通过 tty 设备传输。按下配置的 EOF 键(默认为^D)会立即传输数据,并使任何等待其上的 "read" 返回可用字符数。如果该行已经有数据,这将是一个正常的、非零长度的读取。如果该行为空,则会导致一个零长度的读取,这是文件描述符末尾的定义。因此,stdio 层将把它解释为 EOF 状态。 - R.. GitHub STOP HELPING ICE
@qingfeng:bash与此无关;输入被当前运行的程序处理。 - Keith Thompson
@R..,你的评论应该是一个答案,并且它应该是最顶部的答案。现在很难找到完整的“幕后”信息了... - Neowizard
请注意,当您指示EOF时,流不会关闭;它进入错误状态,但可以通过clearerr()清除,并且您可以再次尝试。如果输入设备是终端,则可能会获得新的输入。如果您打开了文件,则仍需要关闭它(尽管退出程序也会关闭它)。 - Jonathan Leffler

6
除了Jon Lin的关于EOF的回答外,我不确定您编写的代码是否符合您的意图。如果您想要在变量中看到从getchar返回的值,您需要将while语句更改为:
    while((d=getchar())!=EOF) {

这是因为不等运算符的优先级高于赋值。所以在你的代码中,d 始终为 01

你非常细心,这真的很好。但我只是想验证表达式 d=getchar()!=EOF 的值是0还是1。 - Sam
@Sam:你可以通过写成while ((d = (getchar() != EOF)) != 0)或者while ((d = (getchar() != EOF)))来明确表达你正在将比较的结果赋值给d,这样编译器就不会警告你了。更常见的替代方案是while ((d = getchar()) != EOF),它将getchar()的结果赋值给d,然后再将其与EOF进行比较,以避免编译器警告。许多现代编译器都会对你所写的内容生成警告。 - Jonathan Leffler

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