getchar() 在第二次调用时不断返回 EOF 值

getchar() keeps returning EOF value when called second time

提问人:Siddhant Sood 提问时间:4/23/2022 最后编辑:Jonathan LefflerSiddhant Sood 更新时间:4/23/2022 访问量:177

问:

我难以理解和. 我正在尝试运行以下代码:getchar()EOF

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char c;
    int a = 0; //no. of characters
    while (1) {
        c = getchar();
        if (c == EOF) {
            // printf("%i",c); 
            break;
        }
        putchar(c);
        ++a;
    }
    printf("%i", a);
    int b;
    while ((b = getchar()) != EOF) {
        putchar(b);
    }
    printf("here"); // to check wether the code written after the loop is executed
}

我通过按两次 Ctrl-D 终止了第一个循环,我发现很多帖子解释了原因。但是每当我尝试在第一个循环后调用该函数时,它都会不断返回,即使第一个循环中的最后一次调用已经读取了它。getchar()EOF

代码编辑器 - VSCode

操作系统 - macOS

c io eof

评论

1赞 Eric Postpischil 4/23/2022
回复“EOF ...那本来已经读过了“:你没有”读“到文件末尾。它不是流中的数据。这是流处于文件结束状态的信息。对于普通文件,这意味着读取位置位于文件末尾,除此之外没有更多数据需要读取。对于交互式流,您可以致电并尝试阅读更多内容。clearerr(stdin)
4赞 mch 4/23/2022
getchar()返回 ,而不是 .您无法将 与 进行比较。intcharcharEOF
0赞 Jonathan Leffler 4/23/2022
请参阅 while ((c = getc(file)) != EOF) 循环不会停止执行,以讨论将 or 的返回值分配给 a 而不是 .getc()getchar()charint
0赞 Jonathan Leffler 4/23/2022
一旦你达到了EOF,你就达到了EOF——至少在像macOS这样理智的类Unix系统上是这样。Linux 上存在(可能仍然存在)一个问题,如果输入是终端,EOF 并不总是意味着 EOF——IMO,它曾经/是一个错误;它与我所知道的所有其他 Unix 变体相矛盾。如果要“读取过去的 EOF”,则需要用于清除流中的 EOF 和错误位。clearerr(stdin);
0赞 Jonathan Leffler 4/23/2022
在 Ubuntu 22.04 上的测试表明 Linux/Glibc 不再具有“EOF 不是真正的 EOF”错误功能。我忘记了这是多久以前的问题(但我确信这是本千年,而且可能在过去十年内);你很可能不会遇到它。

答:

1赞 chqrlie 4/23/2022 #1

必须定义为 以适应 中可能返回值的全部范围,即 type 的所有值和特殊的负值(通常定义为 )。cintgetchar()unsigned charEOF(-1)

在大多数 unix 系统上,当以规范模式在终端中键入时,终端缓冲的任何输入都会发送到进程。在您的情况下,它会导致输入被回显。如果没有此类待处理的输入,终端将向进程发送零字节,操作系统将其解释为文件末尾。连续点击两次,或者更准确地说,在读取请求的开头,不会输入字节,而是向读取过程发出文件结束的信号,因此任何进一步尝试从流中读取的尝试都将立即返回,而不会请求更多用户输入来自终端。Ctrl-DCtrl-DEOFEOF

评论

0赞 Eric Postpischil 4/23/2022
Control-D 实际上并不发出 EOF 信号。如果键入“abc”、control-D、“def”,则不会显示 EOF。
0赞 chqrlie 4/23/2022
@EricPostpischil:事实上,Ctrl-D 必须在读取请求的开头键入,以表示文件结束。
1赞 Jonathan Leffler 4/23/2022
如果在行上键入了任何数据(在换行符之前),则必须连续键入 <kbd>control-D</kbd>;第一次发送已在输入行中输入的任何内容,第二次表示“零可用字符”,这就是 EOF 的意思。
0赞 chqrlie 4/23/2022
@JonathanLeffler:是的。我更新了答案,提供了更详细的解释和埃里克答案的链接。
1赞 chqrlie 4/23/2022
@JonathanLeffler:我添加了一个链接到你的精彩答案:)