我们谈谈cin.clear的作用,第一次看到这东西,很多人以为就是清空cin里面的数据流,而实际上却与此相差很远,首先我们看看以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <iostream>
using
namespace
std;
int
main()
{
int
a;
cin>>a;
cout<<cin.rdstate()<<endl;
if
(cin.rdstate() == ios::goodbit)
{
cout<<
"输入数据的类型正确,无错误!"
<<endl;
}
if
(cin.rdstate() == ios_base::failbit)
{
cout<<
"输入数据类型错误,非致命错误,可清除输入缓冲区挽回!"
<<endl;
}
system
(
"pause"
);
}
|
我们定义要输入到的变量是整型,但如果我们输入了英文字母或者汉字,那就会发生错误,cin里有个方法能检测这个错误,就是cin.rdstate(); 当cin.rdstate()返回0(即ios::goodbit)时表示无错误,可以继续输入或者操作,若返回4则发生非致命错误即ios::failbit,则不能继续输入或操作.而cin.clear则可以控制我们此时cin里对这个问题的一个标识.语发如下: cin.clear(标识符); 标识符号为:
goodbit 无错误
Eofbit 已到达文件尾
failbit 非致命的输入/输出错误,可挽回
badbit 致命的输入/输出错误,无法挽回 若在输入输出类里.需要加ios::标识符号
通过cin.clear,我们能确认它的内部标识符,如果输入错误则能重新输入.结合真正的清空数据流方法cin.sync(),请看下例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include <iostream>
using
namespace
std;
int
main()
{
int
a;
while
(1)
{
cin>>a;
if
(!cin)
//条件可改写为cin.fail()
{
cout<<
"输入有错!请重新输入"
<<endl;
cin.clear();
cin.sync();
//清空流
}
else
{
cout<<a;
break
;
}
}
system
(
"pause"
);
}
|
上面的cin.clear()默认参数为0,即无错误,正常操作.当我们输入英文字母'k'时,它的状态标识改为fail,即错误,用cout对用户输出信息,再用cin.clear让错误标识改回为0,让我们可以继续输入,再清空流数据继续输入.如果我们没有了cin.clear,则会进入死循环,其过程为我们输入了英文字母,它的状态标识便为fail,当运行到条件判断时,便总是回到错误的条件表示里,并且我们再也没办法输入,因为错误的表示关闭了cin,所以会进入死循环.
cin的总结
近日浏览优快云,发现经常会有关于cin的问题
参考文献:
http:
//blog.youkuaiyun.com/daineng/archive/2008/04/05/2252730.aspx
http:
//www.augustcouncil.com/~tgibson/tutorial/iotips.html
http:
//hi.baidu.com/bdruiruili/blog/item/5966d9958a6eb20c7bf4801f.html
http:
//www.cplusplus.com/reference/iostream/istream/
建议看看:Tips and Tricks
for
Using C++ I/O (input/output)
在cin>><
int
/
float
/
double
>时 如果我们输入一个字符,就会导致刷屏的结果。这是因为非数字字符无法被cin接收而一直停留在输入缓冲区,从而导致下一次cin时直接从缓冲区中读取数据,但是字符无法读取,导致死循环。
那么怎么解决呢?
第一、 在cin>><
int
/
float
/
double
>后加cin.ignore(); cin.clear();
第二、 在cin>><
int
/
float
/
double
>后加
fflush
(stdin); (需要#include <cstdio>) cin.clear()
cin.clear()可以清除输入错误后的相应流状态,而ignore和
fflush
都是起到刷新输入缓冲区的作用(输入的字母留在了缓冲区,cin不能读取,如果不刷新,之后cin还是首先读到字母,导致死循环),从而是cin可以重新接收新的数据。
fflush
刷新缓冲区相信大家都不陌生了,这里就不多说了,那么ignore()方法是怎样操作的呢?
以下参考C++ Reference:
ignore()方法原型是:
istream& ignore ( streamsize n = 1,
int
delim = EOF );功能:它从输入序列提取字符并且丢弃它们,ignore方法直到丢弃的字符数达到 n 或者丢弃的字符是 delim 时(注意,delim 也会一起被丢弃),终止函数。
参数:
n 丢弃的最大字符数, 它是 streamsize.整数类型
delim 界限符
返回值:
函数返回 *
this
流状态有三种:
1) stream:: badbit
系统级的故障,如无法恢复的读写错误,流通常无法继续使用。
2) stream::failbit
可恢复的流错误,如在希望获得数值型的数据时输入了字符,
3) stream::eofbit
文件结束,同时还会设置failbit标志
流有三个函数来测试以上各个流状态:即bad(), fail()和eof(),另外流状态是否正常可以用good()来测试;流的状态字可以由rdstate()读出;另外还有两个操作用于改变流的状态:clear()和setstate(),但它们的操作结果不怎么符合我们的直觉。(注:C++ Reference中的解释是:Sets a
new
value
for
the error control state.)
setstate必须有个一个表示流状态的参数,操作结果将使指定的状态位置位(set),其他的状态位不变,无法作reset操作。clear用于设置流的状态为参数指定的状态字,它实际上是个set操作,而不是reset,它的参数有一个默认的值为goodbit,这实际是个0,等价于clear(0); 不带参数调用时就是clear状态,带参数时,并不是我们想象中的reset参数指定的位,而是将整个状态字设置成参数指定的那样。
具体的请看basic_ios.h中的代码:
/* g++ (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21) */
void
clear(iostate __state = goodbit);
void
setstate(iostate __state)
{
this
->clear(
this
->rdstate() | __state;}
以一个例子作为参考:(C++ Primer里面的一个例子)
#include <stdexcept>
#include <iostream>
#include <cstdio>
using
namespace
std;
int
main()
{
int
ival;
while
(cin>>ival, !cin.eof())
{
if
(cin.bad())
throw
runtime_error(
"IO stream corrupted"
);
if
(cin.fail())
{
cout <<
"rdstate()函数的返回值: "
<< cin.rdstate() << endl;
cout <<
"三个标记位返回的返回值: "
<< cin.fail() << cin.bad() << cin.eof() << endl;
cout <<
"goodbit标记位的返回值: "
<< cin.good() << endl;
//cin.clear(istream::failbit); // 这样不行
//cin.clear(istream::failbit ^ cin.rdstate()); // 可以
//cin.ignore();
cin.clear();
fflush
(stdin);
cerr <<
"bad data, try again:"
<<endl;
//system("PAUSE");
continue
;
}
cout <<ival <<endl;
}
system
(
"PAUSE"
);
return
0;
}
上面的例子修正了C++ Primer书上的例子
用了2种方法清除输入错误:
cin.clear();
fflush
(stdin);
和
cin.ignore();
cin.clear();
其中,cin.clear()可以替换为:cin.clear(istream::failbit ^ cin.rdstate());
也许大家对cin.rdstate()不太熟悉,简要说明一下:
它的原型是:iostate rdstate ( )
const
;它的功能是返回流的当前内部错误标志,他的返回值是eofbit、failbit、badbit和goodbit的任意组合。