C语言中的文件结束符(EOF)

83

我目前正在阅读Ritchie和Kernighan合著的C语言编程书籍。我对getchar()函数中EOF的用法感到困惑。

首先,我想知道为什么EOF的值为-1以及为什么getchar()!=EOF的值为0。非常抱歉我提出这个问题,但我真的不明白。我尝试过了,但是还是不懂。

然后,我尝试运行书中的示例,使用以下代码计算字符数,但似乎即使我按下回车键,也无法退出循环,所以我想知道何时才会到达EOF?

main(){
   long nc;
   nc = 0;
   while (getchar() != EOF)
       ++nc;
   printf("%ld\n", nc);
}
然后,我在Problem with EOF in C上看到了同样的问题。 大多数人建议使用终止符\ n或空终止符'\0'代替EOF,这非常有道理。 这是说示例书中的代码有另外的用途吗?

12
你明白你所提到的那本书是由C语言的原始作者编写的,对吗? - David Gelhar
3个回答

123

EOF表示“文件结束”。换行符(当您按下enter键时发生的情况)并不是文件的结尾,它只是一行的结尾,因此换行符不会终止这个循环。

代码并没有错[*],只是它不做你似乎期望的事情。它读取到输入的结尾,但你似乎只想读取到一行的结尾。

EOF的值为-1,因为它必须与任何实际字符的getchar返回值不同。因此,getchar将任何字符值作为无符号字符转换为int返回,因此其值将为非负数。

如果您在终端上打字,并且想触发文件结束符,请使用CTRL-D(Unix风格的系统)或CTRL-Z(Windows)。然后,在所有输入被读取后,getchar()将返回EOF,因此getchar() != EOF为false,循环将终止。

[*]好吧,如果由于整数溢出而输入超过LONG_MAX个字符,则其具有未定义的行为,但在一个简单的例子中我们可能可以原谅它。


我现在知道问题所在了...这就是为什么我看不到结果...因为我正在使用Dev-C++,它没有system("pause"),所以我需要在代码结尾处输入它。 - newbie
6
实际上,CTRL+D并不会引发EOF(文件结束符)。它只是终止了您的终端,从而内核知道没有更多的字节可以被读取,因此标准输入文件描述符中没有可用的数据。 - Koray Tugay
@newbie system函数创建一个新的shell并运行传递给它的命令。该命令由系统shell执行,与编译器无关。 - phuclv
1
如果您按下回车键“enter”,'getchar()'只会看到一个字符,并且您的“nc”变量会增加。 - EsmaeelE
@KorayTugay Bash的行为是在接收到来自Control-D的EOF字符时退出shell:https://unix.stackexchange.com/questions/110240/why-does-ctrl-d-eof-exit-the-shell - PythonDreams

26

EOF的值为-1是因为它被定义成这样。这个名字是由你所#include 的标准库头文件提供的。它等于-1是因为它必须是一个不能被 getchar() 误认为是实际读取的字节的东西。 getchar() 使用正数(从0到255)来报告实际字节的值,所以-1对此没有问题。

!= 操作符表示 "不等于"。0代表假,任何其他值都代表真。所以发生的是,我们调用 getchar() 函数,并将结果与 -1(EOF)进行比较。如果结果不等于EOF,则结果为真,因为不相等的事物不相等。如果结果等于 EOF,则结果为假,因为相等的事物不是(不相等)。

当你到达“文件结尾”时,调用getchar() 返回EOF。就C而言,“标准输入”(你通过在命令窗口中键入数据来提供给程序的数据)就像一个文件。当然,你总是可以继续输入更多内容,所以需要一个明确的方式来表示“我已经完成了”。在Windows系统上,这是control-Z。在Unix系统上,这是control-D。

书中的例子并没有错。它取决于你实际想要做什么。读取直到EOF意味着你读取了所有内容,直到用户说“我完成了”,然后就不能再读取了。读取直到 '\n' 意味着你读取了一行输入。如果你期望用户键入输入,那么读取直到 '\0' 是一个不好的主意,因为使用键盘在命令提示符下产生此字节要么很难,要么就是不可能的 :)


11

这是很多问题。

  1. 为什么 EOF 是 -1:通常在 POSIX 系统调用中,返回 -1 表示错误,因此我想这个想法是“EOF 类似于错误”。

  2. 任何布尔运算(包括 !=)在 TRUE 时返回 1,在 FALSE 时返回 0,因此当 getchar() != EOF 为 FALSE 时,意味着 getchar() 返回了 EOF

  3. 为了在从 stdin 读取时模拟 EOF,请按下 Ctrl+D


布尔运算返回非零值代表真,返回零代表假。两者是有区别的。 - JUST MY correct OPINION
7
不,这些运算符被定义为返回1。在布尔上下文中(例如if()while()条件语句中),任何非零值都被视为“真”。 - David Gelhar

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