我正在(重新)学习编程,我从C开始。我的IDE(如果我可以这么说的话)是cygwin(32Bit)和Visual Studio 2010,都在Windows7上。我总是用gcc(cygwin)和VS2010编译器编译我编写的代码。我这么做,我想是因为我认为这是一种很好的学习方式。无论如何,我刚刚了解了fflush(stdin),即刷新stdin缓冲区。这似乎是一个很好的功能,因为否则,使用scanf似乎很痛苦。所以我根据我课本上的一个例子写了下面的代码。它使用cygwin中的gcc以及VS2010进行编译。当我运行VS编译的程序时,它工作正常(s.below),当我在cygwin中运行gcc编译的程序,fflush(stdin)不会刷新stdin缓冲区(s.bellow)。我读过一些关于fflush(stdin)在某些情况下具有未定义行为的线程。不管这意味着什么,我都是从C for Linux编程教材中学习的。如果fflush(stdin)不是清除stdin缓冲区中内容的有效方法,还有什么其他标准方法?
非常感谢你的回答!
==在Windows:下运行的程序
enter a long integer and a double
23.00 78.99
lint = 23
dt = 0.00
enter a five digits input
78493
u entered 78 and 493
==程序在Cygwin:中运行
enter a long integer and a double
23.00 78.99
lint = 23
dt = 0.00
enter a five digits input
u entered 78 and 2665720
===代码===
long lint;
double dt;
int fp, sp;
char fn[50], ln[50];
/* using the l modifier to enter long integers and doubles */
puts ("enter a long integer and a double");
scanf("%ld %lf", &lint, &dt);
printf("lint = %dndt = %.2fn", lint, dt);
fflush(stdin); /*DOES NOT WORK UNDER CYGWIN!?*/
/* use field width to split input */
puts("nenter a five digits input");
scanf("%2d %3d", &fp, &sp);
printf("u entered %d and %dn", fp, sp);
C11在7.21.5.2.2说(强调矿):
如果
stream
指向输出流或更新流操作未输入,fflush
函数会导致该流的任何未写入数据以被传送到主机环境以被写入文件否则,行为未定义
这意味着您不应该在输入流上调用fflush
(除非您正在为定义行为的特定操作系统和库编写代码)
这是有充分理由的!你通常会认为fflush(stdin)
会刷新你刚刚输入的行,对吧?好吧,还有更多。想象一下,像这样运行你的程序:
$ ./program < input_file
在这种情况下,理论上所有文件都已经在stdin
的缓冲区中。因此,刷新缓冲区等于结束输入,这是一个非常无用的操作。由于这些原因,fflush
不能在输入流上具有非常合理的行为,这就是为什么它在输入流中没有定义的原因。
如果你想忽略当前行,有更好的方法
void flush_line(FILE *fin)
{
int c;
do
{
c = fgetc(fin);
} while (c != 'n' && c != EOF);
}
这将逐个字符读取输入,并停止,直到出现文件末尾、读取错误或行末尾。
在标准中,没有为输入流定义fflush()。在微软的文档中,它是明确定义的。
结果是,虽然你可以将它与微软的C库一起使用,并明确定义行为,但这种行为是不可移植的。
如果你想使用GCC并完成这项工作,那么你可以使用MinGW/GCC,因为它使用的是微软的C运行时,而不是glibc。
您不应该fflush输入流。你观察到的差异来自于这样一个事实,即这种操作的行为是不明确的。
据我所知,您正在为Linux编写此程序,信不信由你,fflush(stdin)
只能在Windows下工作。(这至少是我从我的C书中得到的,书中称C为假人)。Linux上fflush(stdin)
的替代方案是fpurge(stdin)
。试试看它是否对你有用。