我不确定我是否正确理解了C中的冲洗方式。我只是无法按照多本手册和参考书中的描述使其工作。以下是评论的示例:
#include <stdio.h>
int main(void) {
int x;
char ch;
printf("Prompt: ");
scanf("%d", &x); /* I key in 67 and press Enter. At this very moment,
the input buffer should contain the ASCII codes
for the numbers 6 and 7 as well as the ASCII code
for the newline character, which is 10. The scanf
function is going to find the ASCII codes for 6
and 7, convert them to the integer 67, assign it
to the variable x and remove them from the
buffer. At this point, what still remains in the
buffer is the newline character. */
fflush(stdin); /* I want to do some more input. So, I flush the
buffer to remove anything that still might be
there, but it doesn't really look like fflush is
doing that. */
printf("Prompt: "); /* I'm not going to be able to get my hands on
the following line of code because fflush is
not doing its job properly. The remaining
newline character is going to be read into the
variable ch automatically, thus not allowing
me to enter anything from the keyboard. */
scanf("%c", &ch);
printf("x: %d, ch: %d\n", x, ch);
/*
OUTPUT:
Prompt: 67
Prompt: x: 67, ch: 10
*/
return 0;
}
答案 0 :(得分:4)
不要fflush(stdin);
,它会调用undefined behavior。
引用C11
,
Ifstream指向最近的输出流或更新流 如果没有输入操作,fflush函数会导致该流的任何未写入数据 要传递到主机环境以写入文件; 否则,行为是 未定义。强>
和stdin
不是输出流。
答案 1 :(得分:2)
为了完成起见:
某些实现确实在输入流上定义fflush
。例如Microsoft's msvcrt和GNU libc。其他的,比如BSD libc,可能另外提供separate function来清除缓冲区。
除了不可移植之外,这些功能还有一些严重的缺点:它们通常假设缓冲区看起来有某种特定的方式,例如:只有一个换行符。
stdin
可能连接到文件,其缓冲区可能不仅仅包含换行符。如果输入流被清除,则将跳过这些缓冲的数据。
此外,libc stdio
之外的缓冲区可能没有受到影响。
因此,您应该明确阅读并丢弃您不想要的数据。
答案 2 :(得分:1)
除了Sourav指出的输入流上没有定义fflush()
之外......
我键入67并按Enter键。在这个非常时刻, 输入缓冲区应包含ASCII代码 数字6和7以及ASCII码 对于换行符,即10.扫描 函数将找到6的ASCII码 和7,将它们转换为整数67,分配它 到变量x并从中删除它们 缓冲。在这一点上,仍然存在的是什么 buffer是换行符。
如果用户确实输入了不是数字的内容,则可能发生其他事情。
如果在第一个数字之前存在非数字, x
将不会被初始化。你不会知道,因为你没有检查返回值
scanf()
。
用户可能已预料到下一个提示(对于某个角色),并输入了类似67 x
的内容,期望67
满足您的第一个提示,而x
则是您的第二个提示。 (并且他不会高兴你的节目丢失了部分内容。)
在输入中使用*scanf()
,你不能确定具有预期的格式(用户输入,而不是回读你自己用*printf()
写的东西)是脆弱的
所以我的通用建议是不在用户输入上使用*scanf()
函数,而是使用fgets()
逐行读取用户输入,并在内存中解析输入内容闲。强>
您可以使用许多功能更强大的功能,并且可以处理更细粒度的错误条件(包括在任何错误消息中输入完整行的功能)。 / p>
以下只是一个粗略的观点;根据您的应用程序,您需要以不同的方式进行组织:
const size_t BUFFERSIZE = 1024;
char buffer[ BUFFERSIZE ];
long x;
char ch;
printf( "Prompt: " );
if ( fgets( buffer, BUFFERSIZE, stdin ) == NULL )
{
// Error occurred, use feof() / ferror() as appropriate
}
else
{
size_t len = strlen( buffer );
if ( buffer[ len - 1 ] != '\n' )
{
// The line entered was too long for the buffer,
// there is unread input. Handle accordingly, e.g.
// resizing the buffer and reading the rest.
}
else
{
// You got the whole line; blot out the newline
buffer[ len - 1 ] = '\0';
// Assuming a decimal number first
char * curr = buffer;
errno = 0;
long x = strtol( curr, &curr, 10 );
if ( errno == ERANGE )
{
// Number exceeds "long" range, handle condition
}
else if ( curr == buffer )
{
// What you got was not a number, handle condition
}
// Keep parsing until you hit end-of-string
}
}