C++ Windows 控制台清空包含多次回车的输入缓冲区!全网唯一解决方案

149 阅读3分钟
#include <conio.h>
int main()
{
	std::cout<<"按任意键继续";
	getch();
	return 0;
}

上述代码意图实现的功能,显然就是希望确保用户看到提示信息后,按下任意键,再继续执行下面的代码。但是,有经验的程序员马上就会发现这样的代码是不可靠的:用户完全有可能在看到提示信息之前的任何时候多次按动键盘,这些按键将被存储在输入缓冲区中。执行getch()时,将直接从缓冲区读入一个字符然后继续执行下去,而不会等待用户输入。

为了解决这个问题,显然需要在getch之前清空输入缓冲区。然而,搜索互联网发现,网上已有的解决方案均不能稳健地解决此问题,主要都来自万恶的CSDN:

四种清空输入缓冲区的方法

此文章提供以下两种方法:

std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
while (getchar() != '\n');

这两种方法原理基本一样,就是不断地忽略字符,直到遇到回车。这两种方法也是我搜索到最广泛流传的方法,然而实测这样做非常不可靠!有两种情形都会导致此方法产生意外结果:

  • 输入缓冲区为空。因为这两种方法都不会在缓冲区为空时自动放弃,而会继续等待新的用户输入,并且继续忽略。也就是说,此时用户任何新的输入都会被直接忽略掉。
  • 输入缓冲区包含多个换行符(例如用户在之前狂按过多次回车)。此时这两种方法都会忽略到第一个换行符为止,那之后的输入仍然不会被清空。

尽管存在着两个重大缺陷,这两种愚蠢的方法还是被大量CSDN文章无脑转载,制造大量网络垃圾。

C/C++ 输入缓冲区清除 防止上一次输入会影响下一次输入

此文章除了上述两种万恶之源外,还提供了一种新的方法:

std::cin.sync();

同样地,此方法实测无效。实际上,CppReference中已有特别注解image.png 此方法从来不是为了清空缓冲区而设计的——清空只是一种可能的实现而已。然而,这个方法的CSDN转载量仅次于以上两者。

除了CSDN以外,还有一些同流合污的知乎文章,以及其它无脑转载文章,这里一一列出来鞭笞一番:

全网唯一正确的解决方法

while (kbhit())
	getch();

实测只有此方法能不多不少正正好、安全无污染地清空所有在这之前的任何输入,并且丝毫不会影响在这之后的任何输入!这两个函数都在<conio.h>中。如果你觉得好用,欢迎转载,让正确的知识得以传播!