C++中的cin操作想必学过C++的都很清楚吧,cin是一个输入流,可以允许我们从键盘输入一些数据到我们的变量中,但是如果我们输入的数据与我们的变量类型不符合,cin就会出错,小悠在这里讲解一下cin出错的原因以及解决方案.
长话短说直接入题:
首先来看一下下面的代码:
//main_exe.cpp #include<iostream> using namespace std; int main() { int i_n = 5; cout<<"Please input i_n :\n"; cin>>i_n; while(i_n) { cout<<"Please input i_n again:\n"; cin>>i_n; cout<<"The print is excuted\n"; } cout<<"Here is the end of the paragram!\n"; return 0; }
编译--->链接---->执行
1、如果 我们按照 int 类型正常输入 i_n,可以发现一切正常;
2、如果 我们第一个 i_n 输入的不是 int 类型,
例如 cin时; 输入一个字符 'A',程序奇迹般的进入了【死循环】~~~
并且一直重复输出
cout<<"Please input i_n again:\n";
cout<<"The print is excuted\n";
如图:
【 不会跳出 while()循环 】
为什么会进入死循环?
while()中的 cin>> 为什么不执行?
为了更好地解释原因 ,这里先插播一下有关cin的一些基础知识点.
在程序执行时有一个标志变量来标志输入的异常状态,其中有三位标志位分别用来标志三种异常信息,他们分别是:failbit,eofbit,badbit。
这三个标志位在标志变量中是这样分配的:
第2位 | 第1位 | 第0位 |
failbit | eofbit | badbit |
从 MSDN中(看不懂的句子用google翻译) 我们可以查看这三个标志位的作用
to record a loss of integrity of the stream buffer.记录输入或输出流出现无法挽回的致命错误,其状态用bool ios::bad() 提取
to record end-of-file while extracting from a stream. 用于记录文件是否到达结尾,其状态用 bool ios::eof()提取.
to record a failure to extract a valid field from a stream.
记录非致命的 输入输出流错误,用bool ios::fail() 提取
In addition, a useful value is goodbit, where no bits are set.
除此之外还有有个goodbit,但是它没有对应的位,用 bool ios::good() 提取
这四个标记在标志位寄存器对应取值的意义
ios::badbit 001 输入(输出)流出现致命错误,不可挽回
ios::eofbit 010 已经到达文件尾
ios::failbit 100 输入(输出)流出现非致命错误,可挽回
ios::goodbit 000 流状态完全正常, 各异常标志位都为0
了解了上面的意义我们再修改一上面的代码
//main_exe.cpp #include<iostream> using namespace std; int main() { int i_n = 5; cout<<"Please input i_n :\n"; cin>>i_n; cout<<"Please input i_n again:\n"; //新添加 一句输入 cin>>i_n; cout<<"Here is the end of the paragram!\n"; cout<<"i_n is: "<<i_n<<endl; //输出对应的 i_n 结果 return 0; }
我们定义 i_n 是一个 int 整型,"cin>>"流操作是 从键盘输入读入数据,但是这个读入是间接的。
"cin>>" 引发程序中断响应,这里的中断即是键盘输入,我们从键盘输入数据,系统将数据读取后放到缓冲区,cin从缓冲读取所需的数据;
因为 i_n 是一个整型,但是现在缓冲区放的如果是非int 型,例如你输入 ‘s’字符,
这个时候 cin>> 就会失败,i_n不会被写入新的数据(从而保持原有数据);
因为 cin>> 出错,则有failbit位被置1,即是 cin.fail() 返回 true;
在此状态下,cin>> 将不会起作用!
如图:我们以输入字符 'S' 为例:
此时 cin>> 不在起作用,
回顾最上面所说的死循环代码
//main_exe.cpp #include<iostream> using namespace std; int main() { int i_n = 5; cout<<"Please input i_n :\n"; //如果输入字符,cin就会失效! i_n的值不会变化 cin>>i_n; while(i_n) { cout<<"Please input i_n again:\n"; cin>>i_n; cout<<"The print is excuted\n"; } cout<<"Here is the end of the paragram!\n"; return 0; }
由于这种错误只是 failbit标志位引起的,failbit是 非致命性的,所以 我们可以 解决这个问题~~~~
如果我们在输入 i_n 时输入了非数值类型,例如 我们输入了 'S'.
这个时候cin>> 流操作就会失败,【S将会被滞留在缓冲区】, 无法被读出,failbit 位将会被置为 1 ,而当failbit 为 1时,以后的cin>> 流操作将会被跳过(因为有错误了嘛)
由于cin>> 流操作失败了,i_n的值将会保留原有值不变 ,即是i_n依然是原有值 5 ;
当进入 while(i_n) 循环时 i_n 一直为真,cin>>又被忽略,所以会导致死循环;
使用下面的两个函数:
cin.clear();// 清除状态标志位,即是将 所有标志位清 零;
cin.sync();//清空 输入缓冲区全部,包括 '\n'
在cin>>后加入上面的函数,就可以判断是否输入错误,然后做一些纠正处理了,
例如:
int i_n = 5; cin>>i_n; //用于判断 是否cin>>出错,cin.fail()获取 当前 faibit 状态 while(cin.fail()) { cin.clear();//清除掉failbit的错误 cin.sync();//别忘记清除掉缓冲区啊 cout<<"Please intput i_n again \n"; cin>>i_n; if(cin.fail()) {cout<<"Cin error ! You should input a int type \n";return ;} break; }
经过上面的处理,一旦我们发现cin出了错误,我们就清除掉cin的错误标记让cin有效,然后从输入缓冲区清除掉错误的输入,让我们再次输入就OK啦
本文出自 悠然品鉴,转载请务必注明出处:http://www.youranshare.com/blog/sid/65.html