我对C编程很陌生,我试图了解fflush(stdin)
是如何工作的。
在下面的示例中,fflush(stdin)
是清除所有缓冲区,还是清除在第三项之后输入的任何内容?我的意思是用户输入帐号,空格,名称,空格,余额。从这一点开始,用户输入的任何内容都会被fflush(stdin)
刷新吗? 而且stdin
不会是空的。
为什么这么说是因为它进入了一个while循环并开始写入文本文件。
我的第二个问题是Ctrl-Z
是否会告诉操作系统停止要求用户输入?
printf( "Enter the account name and balance. (separated by spaces)n" );
printf( "Enter EOF to end input. (Ctrl-Z)n" );
printf( "? " );
scanf( "%d%s%lf", &account, name, &balance );
fflush(stdin);
// write account, name and balance into file with fprintf
while ( !feof( stdin ) )
{
//fflush(stdin);
fprintf( cfPtr, "%d %s %.2fn", account, name, balance );
printf( "? " );
scanf( "%d%s%lf", &account, name, &balance );
}
fclose( cfPtr );
答案是fflush(stream)
只是为输出流正式定义的,所以fflush(stdout)
是可以的,但fflush(stdin)
不是。
fflush(stream)
的目的是使操作系统将任何缓冲区刷新到基础文件。举个合法使用的例子,如果学生执行以下操作,他们经常会遇到诸如"我的提示没有出现!"之类的问题:
printf("Enter a number: ");
但是,他们发现这很好用:
printf("Enter a number:n");
当然,他们不希望在提示后换行符,所以他们有点问题。
这样做的原因是stdout
的输出由操作系统缓冲,默认行为(通常)只是在遇到换行符时将输出实际写入终端。在printf()
后添加fflush(stdout)
可以解决问题:
printf("Enter a number: ");
fflush(stdout);
现在,通过类比,人们通常认为fflush(stdin)
应该丢弃任何未使用的输入,但如果你稍微考虑一下,那就没有多大意义了。"刷新"输入缓冲区是什么意思?它"冲洗"到哪里?如果刷新输出缓冲区,输出将发送到底层文件或终端,无论如何它最终都会在那里结束,但输入"最终还是会在哪里结束"?无从得知!如果输入流数据来自文件、管道或套接字,则行为应该是什么?对于输入流来说,fflush()
的行为应该是什么根本不清楚,但对于输出流来说,在所有情况下都非常清楚。因此,仅为输出流定义fflush()
。
错误使用fflush(stdin)
变得司空见惯的原因是,许多年前,一些操作系统确实实现了一种方案,其中它按照许多人的预期工作,丢弃了未使用的输入。Microsoft DOS就是一个很好的例子。令人惊讶的是,现代版本的 Linux 也实现了输入流的fflush()
。
处理"额外"不需要的终端输入的正确做法是简单地读取它而不对它执行任何操作。这几乎和调用fflush(stdin)
一样简单,可以在任何地方工作,并且不依赖于形式上未定义的行为。
C 标准说:
如果流指向未输入最新操作的输出流或更新流,则 fflush 函数会将该流的任何未写入数据传递到主机环境以写入文件;否则,行为是未定义的。
POSIX说(也明确服从C标准):
如果流指向未输入最新操作的输出流或更新流,fflush() 将导致将该流的任何未写入数据写入文件,...
但是Linux手册页说:
对于输出流,fflush() 强制写入给定输出的所有用户空间缓冲数据,或通过流的基础写入函数更新流。对于输入流,fflush() 会丢弃从基础文件获取但尚未被应用程序使用的任何缓冲数据。流的打开状态不受影响。
fflush(stdin)
调用未定义的行为。
fflush()
仅为输出流定义。你不应该这样做。
在 Unix 上,Ctrl-Z 发送 TSTP 信号 (SIGTSTP),默认情况下,该信号会导致进程暂停执行。