cin或cout对象包含一个描述流状态(stream state)的数据成员(从ios_base那里继承的)。流状态(被定义为iostate类型,而iostate是一种bitmask类型)由3个ios_bae元素组成:eofbit、badbit或failbit,其中每个元素都是一位,可以是1(设置)或0(清除)。当cin操作到达文件末尾时,它将设置eofbit;当cin操作未能读取到预期的字符时,它将设置failbit。I/O失败(如试图读取不可访问的文件或试图写入到保护的磁盘),也可能将failbit设置为1.在一些无法诊断的失败破坏流时,badbit元素将被设置。当全部3个状态都设置为0时,说明一切顺利。程序可以检查流状态,并使用这种信息来决定下一步做什么。
下表列出了这些位和一些报告或改变流状态的ios_base方法
上表中的两种方法——clear( )和setstate( )很相似。他们都重置状态,但采取的方式不同。clear( )方法将状态设置为它的参数。因此,下面的调用:
clear( );
- 1
将使用默认参数0,这里将清除全部3个状态位(eofbit、badbit和failbit)。同样,下面的调用:
clear(eofbit);
- 1
将状态设置为eofbit;也就是说,eofbit将被设置,另外两个状态位将被清除。
而setstate( )方法只影响其参数中已设置的位。因此,如果failbit被设置,则仍将被设置。
2.流状态的影响
只有在流状态良好(所有的位都被清除)的情况下,下面的if或while测试才能返回true:
while(cin>>input);
- 1
如果测试失败,可以使用上表中的成员函数来判断可能的原因。例如:
while(cin>>input)
{
sum += input;
}
if(cin.eof())
cout<<"Loop terminated because EOF encountered\n";
- 1
- 2
- 3
- 4
- 5
- 6
设置流状态有一个非常重要的后果:流状态对后面的输入或输出关闭,知道位被清除。例如,下面的代码不能正常工作:
while(cin>>input)
{
sum += input;
}
cin>>input;//won't work
- 1
- 2
- 3
- 4
- 5
如果希望程序在流状态位被设置后能够读取后面的输入,就必须将流状态设置为良好(即为0)。这可以通过clear( )函数来实现:
whlie(cin>>input)
{
sum += input;
}
cin.clear();
while(!isspace(cin.get()))
continue;
cin>>input;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
注意,这还不足以重新设置流状态。导致输入循环终止的不匹配输入仍留在输入队列中,程序必须跳过它。一种方法是已知读取字符,直到达到空白为止。isspace( )参数是一个cctype函数,它在参数是空白字符时返回true。另一种方法是,丢弃行中剩余部分,而不仅仅是下一个单词:
while(cin.get()!='\n')
continue;//get rid rest of line
- 1
- 2
这个例子假设循环由于不恰当的输入而终止。现在,假设循环是由于达到文件尾或者由于硬件故障而终止的,则处理错误输入的新代码将毫无意义。可以使用fail( )方法检测假设是否正确,来修复问题。由于历史原因,fial( )在failbit或eofbit被设置时返回true,因此代码必须排除后一种情况。下面是一个排除这种情况的例子:
while(cin>>input)
{
sum += input;
}
if(cin.fail() && !cin.eof())
{
cin.clear();
while(!isspace(cin.get()))
continue;
}
else
{
cout<<"I cannot go on!\n";
exit(1);
}
cin>>input;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
3.其他istream类方法
1)单字符输入,cin.get(ch)与cin.get()
采用哪种单字符输入形式呢?
首先,应该确认是否希望跳过空白。如果跳过空白方便,则使用抽取操作符>>。如果希望检测每个字符,请使用get( )方法。
2)字符串输入:getline( )、get( )和ignore( )
istream & get(char *, int, char);
istream & get(char *, int);
istream & getline(char *, int, char);
istream & getline(char *, int);
- 1
- 2
- 3
- 4
第一个参数是用于放置输入字符串的内存单元的地址。第二个参数比要读取的最大字符数大1(额外的一个字符用于存储结尾的空字符,以便将输入存储为一个字符串)。第三个参数指定用作分界符的字符,只有两个参数的版本将换行符作为分界符。上述函数都在读取最大数目的字符或遇到换行符后为止。
例如,下面的代码:
char line[50];
cin.get(line,50);
- 1
- 2
将字符输入读取到字符数组line中。cin,get( )函数将在达到第49个字符或遇到换行符(默认情况)后停止将输入读取到数组中。get( )和getline( )之间的主要区别在于,get( )将换行符保留在输入流中,这样接下来的输入操作首先看到的将是换行符,而getline( )抽取并丢弃输入流中的换行符。
下面程序演示了getline( )和get( )是如何工作的,它还介绍了ignore( )成员函数。该函数接受两个参数:一个是数字,指定要读取的最大字符;另一个是字符,用作输入分界符。如:
ignore(255, '\n');
- 1
将读取并丢弃接下来的255个字符或直到到达第一个换行符。原型为两个参数提供的默认值为1和EOF,该函数的返回类型为istream &:
istream & ignore(int = 1, int = EOF);
- 1
示例代码:
#include <iostream>
const int Limit = 255;
int main()
{
using std::cout;
using std::cin;
using std::endl;
char input[Limit];
cout<<"Enter a string for getline()processing:\n";
cin.getline(input,Limit,'#');
cout<<"Here is your input: \n";
cout<<input<<"\nDone with phase 1\n";
char ch;
cin.get(ch);
cout<<"The next input character is "<<ch<<endl;
if(ch != '\n')
cin.ignore(Limit,'\n');
cout<<"Enter a string for get()processing: \n";
cin.get(input,Limit,'#');
cout<<"Here is your input: \n";
cout<<input<<"\nDone with phase 2\n";
cin.get(ch);
cout<<"The next input character is "<<ch<<endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
注意:getline( )函数将丢弃输入中的分界字符#,而get( )不会。