输入、输出流状态

        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( )不会。

猜你喜欢

转载自blog.csdn.net/dgreh/article/details/80881602
今日推荐