zoukankan      html  css  js  c++  java
  • 关于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 不太仔细的漏洞,这样子解决之后还是很爽的啦!

  • 相关阅读:
    Apache mod_rewrite
    vim 常用设置
    ssh 和 scp 命令访问非默认22端口。
    gulp常用插件
    gulp+Babel 搭建ES6环境
    ES6类与模块
    Autoprefixer处理CSS3属性前缀
    js模块方案
    ES6转码器babel的使用
    window.history.pushState与ajax实现无刷新更新页面url
  • 原文地址:https://www.cnblogs.com/gaoduan/p/3819059.html
Copyright © 2011-2022 走看看