我用C语言编写了一个简单的程序来测试scanf()函数。它基本上从终端读取,按char
char
,重新打印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 9
、1 8
、1 7
将分别打印在换行符上。
如果在终端上输入987
,然后按Ctrl-D
;则1 9
将打印在同一行上(因为输入987
输入后没有键入Enter
),1 8
,1 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
吗?