今天在写代码的时候,遇到了一个非常奇怪的问题
while (true)
{
int select;
cout << "请输入查找的方式:" << endl;
cout << "1、按职工编号查找" << endl;
cout << "2、按职工姓名查找" << endl;
cin >> select;
if (select == 1)
{
break;
}
if (select == 2)
{
break;
}
else
{
cout << "输入不合法!" << endl;
}
}
这段代码的本意是想要规范输入,提高容错率。但是当我输入一个字符比如’a’的时候,while循环中的cin语句将会被跳过,进入无限的死循环。上网查阅了很多资料,发现了问题所在
MSDN上cin的定义如下
看不懂也没关系,以下为它的翻译
cin
该对象控制从标准输入中以字节流形式进行的提取。构造对象后,调用cin.tie()返回&cout。
因为cin是一个输入流,当要求给一个整型赋值的时候,输入的类型可能与该整型不匹配,导致缓存溢出。如果输入的过多了,那么,那些输入除了一部分赋值给变量以外还有剩余的字节,这些剩余的输入将残留在输入缓存中,就会导致在下面需要输入的时候不再接受输入,而直接从缓存中获得。
所以,出现这个问题后可行的解决方法如下:
一、更换被赋值整型的数据类型
这里使用string类来接收输入,需要先包含头文件string
while (true)
{
string select;
cout << "请输入查找的方式:" << endl;
cout << "1、按职工编号查找" << endl;
cout << "2、按职工姓名查找" << endl;
cin >> select;
if (select == "1")
{
break;
}
if (select == "2")
{
break;
}
else
{
cout << "输入不合法!" << endl;
}
}
string类型是一种顺序表的结构,元素是char类型的字符,这个类型可以根据输入自动分配所占内存空间的大小,string的最大容量取决于机器本身的限制或者字符串所在位置连续内存的大小(一般来说绝对够你用的了,除非你在这个输入位置输进去了一篇几万字的学术论文。)
当采用了string类型来接收数据流的时候,妈妈再也不用担心我会缓存溢出了
(>-<)/
二、使用cin对象中自带的函数清空缓存区
万一,我说的是万一,真的有人想不辞辛劳地输入一篇万字长文来挑战你代码的健壮性,这个时候该怎么办呢?
那当然是把他的头锤爆
那当然是换一种方法从根本上解决问题啊~
cin这个类提供了方法来对缓存区进行清空,以下为方法详解
当cin在接收到错误的输入的时候,会设置状态位good。如果good位不为1,则cin不接受输入,直接跳过。如果下次输入前状态位没有改变那么即使清除了缓冲区数据流也无法输入。所以清除缓冲区之前必须要重置cin的状态位。
在这里我们采用cin类中的clear()函数,具体语法如下
cin.clear();
//如果在前面没有声明命名空间的话,要这样写:
std::cin.clear();
好了,重置了cin的状态位,下面需要进行缓冲区的清理,这里使用的是cin类中的ignore函数(也有使用sync()函数的,但由于程序运行时并不总是知道外部输入的进度,很难控制是不是全部清除输入缓冲区的内容。通常我们有可能只是希望放弃输入缓冲区中的一部分,而不是全部)。语法如下:
//清除输入缓冲区的当前行
cin.ignore(numeric_limits<std::streamsize>::max(),'\n');
//清除输入缓冲区里所有内容
cin.ignore(numeric_limits<std::streamsize>::max());
//清除一个字符
cin.ignore()
好了,清除过后,你的代码就像掌控了兄♂贵♂之♂力一样健壮,再也不怕有熊孩子搞崩你的程序了
第一次写文,好激动a,可能有很多理解不到位或者理解错误的地方,还请大家包涵指正!(话说有人想试试输入一篇万字长文来挑战一下string容器的承受极限吗,欢迎挑战成功的同学在评论区告诉我结果,
顺便留下你内存条的的型号thx
)