网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.

【C++】 cin错误导致的while()死循


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翻译) 我们可以查看这三个标志位的作用

Badbit

to record a loss of integrity of the stream buffer.记录输入或输出流出现无法挽回的致命错误,其状态用bool ios::bad() 提取

 

eofbit

to record end-of-file while extracting from a stream. 用于记录文件是否到达结尾,其状态用 bool ios::eof()提取.

Failbit

to record a failure to extract a valid field from a stream.

记录非致命的 输入输出流错误,用bool ios::fail() 提取

goodbit

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


  • 标签:
  • cin无效
  • cin死循环
  • cin出错
网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.