关于C++ 输入输出流状态控制

关于这一点呢,是在做《C++primer 》关联容器map的一道习题中发现这个蛋疼的问题的。

问题是这样的:

我想要将while循环条件设置为cin,这样就可以不断等待输入,普通的程序可以直接按下ctrl+z中止输入,麻烦在于这里有两层这样的while循环,而ctrl+z会一次性全部退出,导致无法实现想要的目的(在每个外层循环内部,可以输入有限量可中止的内层循环变量,也就是说第一次按下ctrl+z只停止内层的循环,等待进行下一次外层循环,然后再进入内层循环……)

 1 #include<<SPAN style="COLOR: black">iostream>
 2 #include<<SPAN style="COLOR: black">map>
 3 #include<<SPAN style="COLOR: black">string>
 4 #include<<SPAN style="COLOR: black">vector>
 5 using namespace std;
 6 int main()
 7 {
 8     map<<SPAN style="COLOR: black">string, vector<<SPAN style="COLOR: black">pair<<SPAN style="COLOR: black">string, string>>> family;
 9     string family_name;
10    
11     while (cin)                                                            //输入流状态正常就持续输入,ctrl+z可使其错误而退出                    
12     {  
13         cout << "please input the family name: " << endl;
14         cin >> family_name;
15  
16         vector<<SPAN style="COLOR: black">pair<<SPAN style="COLOR: black">string, string>> children;             //vector>,用于给family的second赋值
17         pair<<SPAN style="COLOR: black">map<<SPAN style="COLOR: black">string,vector<<SPAN style="COLOR: black">pair<<SPAN style="COLOR: black">string,string>>>::iterator,bool> ret=family.insert(make_pair(family_name, children));                                                                  //取insert的返回值
18  
19         if (!ret.second)                                                    //插入失败,表面之前map里面存在此键
20         {
21             cout << "the family name you give is already exist!" << endl;
22             continue;
23         }
24  
25         string child_name, birthday;
26         cout << "please input the children name and birthday: " << endl;   
27        
28         while (cin >> child_name >> birthday)                   //输入child_name、birthday来初始化vector
29         {  
30            
31             ret.first->second.push_back (make_pair(child_name, birthday) );
32                                                    //ret.first为map>>,->second之后表示vector>
33         }
34        
35         cin.clear();              //置流于有效状态,使ctrl+z不会直接退出所有的cin,而只退出上面的cin>>child_name>>birthday
36     }
37  
38  
39     map<<SPAN style="COLOR: black">string, vector<<SPAN style="COLOR: black">pair<<SPAN style="COLOR: black">string, string>>>::iterator iter_map = family.begin();  //迭代器遍历,输出key对应的value
40     while (iter_map != family.end())
41     {
42         cout << "family_name: " << iter_map->first << endl;
43  
44         vector<<SPAN style="COLOR: black">pair<<SPAN style="COLOR: black">string, string>> vec = iter_map->second;
45         vector<<SPAN style="COLOR: black">pair<<SPAN style="COLOR: black">string, string>>::iterator iter_vec = vec.begin();
46  
47         while (iter_vec != vec.end())
48         {
49             cout << "   ";
50             cout << "children name: " << iter_vec->first << endl;
51             cout << "   ";
52             cout << "birthday:      " << iter_vec->second << endl;
53             ++iter_vec;
54         }
55        
56         ++iter_map;
57     }
58  
59     system("pause");
60     return 0;
61 }

我们来分析一下面临的问题:

 

将cin >> value (某个变量)放在while的条件中是常见的等待输入的手段,那么如何中止循环呢?

使用ctrl+z组合键,可以中止循环,那么ctrl+z到底是怎么实现的呢?

 

下面是个人的理解和分析:

 

原来,ctlr+z是通过将输入流对象的条件状态设置为failbit来使cin>>value为false的,

输入流对象有badbit、failbit、eofbit以及有效等状态,分别对应于硬件错误导致被破坏的流状态、输入不匹配等造成的错误、文件中止导致流的结束、以及有效的流状态。

 

而通过cin.eof()、cin.fali()、 cin.bad()、 cin.good()的调用可以知道当前流的状态,比如:当前处于failbit状态,则cin.fail()返回true

 

这里还要介绍一个cin.clear()函数,可以将流状态值重置为有效。

 

下面用一段测验代码来说明:

#include<<SPAN style="COLOR: black">iostream>
using namespace std;
int main()
{
    int a;
   
        while (cin >> a)
        {
            cout << "!" << endl;
        }
        //cin.clear();
       
        if (cin.bad())
            cout << "bad!" << endl;
        else if (cin.fail())                //ctrl+z使其fail
            cout << "fail!" << endl;
        else if (cin.good())
            cout <<"good!" << endl;
   
    system("pause");
    return 0;
}

测验时,在输入几个数字后就按下ctrl+z

若无cin.clear()的调用,输出为fail!

    有cin.clear()的调用时,输出为good!

说明,ctrlz+z使流状态变为failbit,而clear可以重置其为有效状态

 

接下来:

#include<<SPAN style="COLOR: black">iostream>
using namespace std;
int main()
{
    int a, b;
    while (cin >> b)
    {
        cout << "#" << endl;
        while (cin >> a)
        {
            cout << "!" << endl;
        }
        //cin.clear();
        
        if (cin.bad())
            cout << "bad!" << endl;
        else if (cin.fail())               
            cout << "fail!" << endl;
        else if (cin.good())
            cout << "good" << endl;
    }
    
    if (cin.bad())
        cout << "bad!!!!" << endl;
    else if (cin.fail())                
        cout << "fail!!!!" << endl;
    else if (cin.good())
        cout << "good!!!" << endl;
    system("pause");
}

双层while循环嵌套,

这时候,若无cin.clear()

当按下ctrl+z时可以发现,它将直接退出两层循环!

也就是说,ctrl+z可以直接令循环内外的cin的状态均为failbit

而加入cin.clear()代码后

        发现,这时候只退出了内层循环,内层循环是goodbit,程序在等待外层的输入,再次按下ctrl+z,发现此时的外层是failbit

(要将缩进应用于写作当中,哈哈哈!)

 

这样就基本了解清楚了ctrl+z和cin使用的一些内容和注意事项,每次学习遇到这种小细节的时候总是很令人纠结的,但是解决之后会觉得很是神奇,在学习STL 使用的时候解决了一个之前阅读IO 不太仔细的漏洞,这样子解决之后还是很爽的啦!

posted @ 2014-07-01 21:16  羽加迪姆勒维奥萨  阅读(315)  评论(0编辑  收藏  举报