因此,快速Google搜索fflush(stdin)
以清除输入缓冲区会显示许多网站警告不要使用它。然而,这正是我的CS教授教授课程的方式。
使用fflush(stdin)
有多糟糕?即使我的教授正在使用它并且它似乎完美无缺地工作,我是否真的应该避免使用它?
答案 0 :(得分:65)
简单:这是未定义的行为,因为fflush
意味着在输出流上调用。这是C标准的摘录:
int fflush(FILE * ostream);
ostream指向输出流或 最新的更新流 最近的操作没有输入, fflush功能导致任何未写入 要传递的流的数据 到要写的主机环境 到文件;否则,行为 未定义。
所以这不是一个“多么糟糕”的问题。 fflush(stdin)
明显错误,一定不能使用。
答案 1 :(得分:18)
根据标准,fflush
只能与输出缓冲区一起使用,显然stdin
不是一个。但是,some编译器提供了fflush(stdin)作为扩展的用法。在这种情况下,您可以使用它,但它会影响可移植性,因此您将无法再在地球上使用任何符合标准的编译器并期望获得相同的结果。
答案 2 :(得分:2)
我相信您不应该永远呼叫fflush(stdin)
,原因很简单,您甚至根本不需要尝试刷新输入。实际上,您可能以为只有一个原因,那就是:克服scanf
被卡住的错误输入。
例如,您可能有一个程序坐在循环中,使用scanf("%d", &n)
读取整数,并且您发现用户第一次键入像'x'
这样的非数字字符, the program goes into an infinite loop。
面对这种情况,我相信您基本上有三种选择:
fflush(stdin)
,则通常建议通过调用getchar
读取字符直到\n
)。scanf
to read input。现在,如果您是初学者,那么scanf
似乎就像最简单的读取输入法一样,因此选择#3既麻烦又困难。但是#2似乎是真正的解决方案,因为每个人都知道用户不友好的计算机程序是一个问题,因此最好做得更好。因此,太多的新手程序员陷入了困境,觉得他们别无选择,只能做#1。他们或多或少不得不使用scanf
进行输入,这意味着它会卡在错误的输入上,这意味着他们必须找出一种方法来清除错误的输入,这意味着他们非常想使用{ {1}}。
我想鼓励所有新手程序员进行一系列不同的权衡:
在C编程职业生涯的最初阶段,在您习惯使用fflush(stdin)
以外的任何内容之前,只需不要担心输入错误。真。继续并使用上面的#2。这样思考:您是一个初学者,很多事情您尚不知道该怎么做,而您尚不知道如何做的一件事是:应对意外的输入。 / p>
learn how to do input using functions other than scanf
。到那时,您可以开始优雅地处理错误的输入,并且您将获得更多,更好的技术,这些技术根本不需要尝试清除错误的输入。
或者,换句话说,仍然坚持使用scanf
的初学者应该随意使用COPY-OUT#2,并且当他们准备就绪时,应该从那里升级到#3,而没有人应该使用正在使用技巧1尝试完全清除输入(当然不能使用scanf
。
答案 3 :(得分:2)
使用fflush(stdin)
刷新输入有点类似于dowsing for water,使用的形状是字母“ S”。
以某种“更好”的方式帮助人们冲洗输入,就像冲上S型棍推土机,然后说:“不,不,您做错了, 您需要使用Y型棒!”。
换句话说,真正的问题不是fflush(stdin)
不起作用。调用fflush(stdin)
是潜在问题的征兆。为什么要完全“刷新”输入? 那是您的问题。
通常,潜在的问题是您正在使用scanf
,它处于许多令人困惑的模式之一,意外地在输入上留下了换行符或其他空格。因此,最好的长期答案是learn how to do input using better techniques than scanf
。
答案 4 :(得分:1)
引自POSIX:
对于打开以供阅读的流,如果文件尚未处于EOF,且文件为1 能够寻找,应设置基础开放文件描述的文件偏移量 到流的文件位置,以及任何被推回到流上的字符 之后没有从流中读取的ungetc()或ungetwc()应该是 梳理(不进一步改变文件偏移量)。
请注意终端无法搜索。
答案 5 :(得分:1)
现有答案均未指出问题的关键方面。
如果您发现自己想要“清除输入缓冲区”,那么您可能正在编写一个命令行交互程序,更准确地说,您想要的是< em>丢弃当前行输入中您尚未阅读的字符。
这不是 fflush(stdin)
所做的。支持在输入流上使用 fflush
的 C 库将其记录为什么都不做, 或丢弃已从底层文件读取但未传递给应用程序的缓冲数据。这很容易比当前行的其余部分更多或更少输入。在很多情况下它可能会偶然工作,因为终端驱动程序(在其默认模式下)一次一行地向命令行交互程序提供输入。但是,当您尝试从磁盘上的实际文件(可能用于自动测试)向程序提供输入时,内核和 C 库将切换到以大“块”(通常为 4 到 8 kB)的形式缓冲数据,而无需与行边界的关系,你会想知道为什么你的程序要处理文件的第一行,然后跳过几十行并在下面一些明显随机的行的fflush(stdin)
获胜不要全部跳过。
那你应该怎么做呢?我更喜欢的方法是,如果您一次处理输入一行,则一次读取整行。 C 库具有专门用于此的函数:fgets
(在 C90 中,因此完全可移植,但仍然让您以块的形式处理很长的行)和 getline
(特定于 POSIX,但将管理 { {1}} 为您编辑了缓冲区,以便您可以一次处理所有长行,无论它们有多长)。通常从处理“当前行”的代码直接从标准输入转换为处理包含“当前行”的字符串的代码。