C scanf() 函数,如何在 EOF/EOT 上终止?



我用C语言编写了一个简单的程序来测试scanf()函数。它基本上从终端读取,按charchar重新打印return value和读取char;并在满足 EOF/EOT 或读取n newline时终止。

#include <stdio.h>
#include <stdbool.h>
int main(void) {
char c; int ret;
printf("Enter the chars to test: ");
//LOOP (scan & print) only when return is not EOF and char is not newline
while ( ((ret = scanf("%c", &c)) != EOF) && c!='n' ) {
printf("%i %cn", ret, c);
}
return 0;
}

如果按下换行符(Enter),它将正确终止。但它不会只用一个Ctrl-D终止。单个Ctrl-D将刷新键入的"字符"并打印它们。然后之后它将再次等待输入,尽管Ctrl-D已发送了EOF。如果我们在第 1 次 (2x) 之后直接再次按Ctrl-D次或只是Enter它将终止。因此,您将需要连续两个Ctrl-D来终止程序(或在这种情况下的循环)。

例:

如果在终端上输入987,则按Enter;然后1 91 81 7将分别打印在换行符上。

如果在终端上输入987,然后按Ctrl-D;则1 9将打印在同一行上(因为输入987输入后没有键入Enter),1 81 7将打印在换行符上。然后它仍将等待更多输入,除非通过直接输入连续第 2 个Ctrl-D或使用换行符 (Enter终止它。因此,它(程序)只会在连续newline或第 2 次Ctrl-D后停止(退出循环)。

我很困惑。发送的单个Ctrl-D不应该在这里停止循环吗?我应该怎么做才能在收到一个Ctrl-D后停止程序(scanf 循环)?

我在 Lubuntu 19.10 上用 gcc 9.2.1 测试了代码。

问题是scanf()在不再等待输入并遇到EOF之前不会返回EOF。(否则,您的"%c"转换说明符将接受任何字符(包括'n'字符)为有效字符,并将其视为成功转换)

当您键入一行字符时,例如"abcdefg"并尝试按Ctrl+d(指示输入结束),输入 ("abcdefg") 被处理,当达到'g'时,scanf()块等待下一个输入。(因为转换成功且未发生匹配或输入失败)

第二次键入Ctrl+d后(指示输入结束),当没有要处理的输入时,在第一次成功转换之前达到EOF并发生输入失败scanf()然后返回EOF

参见:man 3 scanf --返回值部分和 C11 标准 - 7.21.6.2 fscanf 函数(p16)

测试一个的返回值,而不是EOF。第一次达到 eof 时,返回零。零后的下一个扫描返回EOF

while ( ((ret = scanf("%c", &c)) == 1) && c!='n' ) {
printf("%i %cn", ret, c);
}

此行为是为标准 C 库指定的。

成功

后,该函数返回成功填充的参数列表的项数。此计数可以与预期的项目数匹配,也可以由于匹配失败、读取错误或文件末尾的到达而减少(甚至为零)。

如果发生读取错误或在读取时到达文件末尾,则会设置正确的指示器(feof 或 ferror)。

如果使用更复杂的输入格式,则可以将if (feof(stdin) != 0) break;添加到循环主体中。

如果您只阅读字符,不是更好使用fgetc吗?

最新更新