首页 > 代码库 > 关于C++ 输入输出流状态控制

关于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来初始化vector29         {  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>>birthday36     }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对应的value40     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 不太仔细的漏洞,这样子解决之后还是很爽的啦!