C++ Primer 4th中第八章的一个错误 遗漏了cin.ignore

第八章有个例子,非常简单,就是读入用户输入,赋给一个int,这里面有一个判断,就是如果用户输入的不是int,那么,cin就会变成invalid,里面就有condition state,于是我们可以catch这个state并clear,然后继续读入。

但是书上给的例子有个错误,原来的程序是这样的:

Code: Select all
#include <iostream>
#include <stdexcept>
using namespace std;

int main(int argc, char **argv)
{
    int ival;
    // cout << "Begin state is: " << cin.rdstate() << endl;
    while (cin >> ival, !cin.eof()) {
        // cout << "Current Enter loop state is: " << cin.rdstate() << endl;

        if (cin.bad()) {
            // no catch so the terminate will be called
            throw runtime_error("IO Stream corrupted");
        }

        if (cin.fail()) {
            cerr << "bad data, try again: ";
            cin.clear(istream::failbit);
            // cout << "Current state is: " << cin.rdstate() << endl;
            continue;
        }

        // ok, print out this integer
        cout << "Input correct, your number is: " << ival << endl;
    }
}


这里有两个错误:

(1)在Linux,g++环境下,cin.clear(istream::failbit)并不能清除cin的fail状态,尽管从clear函数的文档上来看应该是可以的。没办法,我改成了cin.clear()就OK了

(2) 遗漏了cin.ignore这个句子或有相同效果的代码。这是因为cin的fail状态虽然被消除了,但是本次读入的错误的用户输入,比如用户输入的是一 个字符串,还存在于cin的buffer中,这样,下次循环cin >> ival照样出错,于是这样就形成了死循环。因为cin的buffer中始终存在着用户第一次输入的错误数据,于是while循环就一直继续着。

后 来我加了这样一句: cin.ignore(100000, '\n'); 就OK了。可以看ignore的文档,代码的意思是ignore buffer中从一开始到第一个\n为止的所有字符,第一个参数故意写的很大,这是因为ignore的第一个参数表示ignore多少个字符,太小会导致 buffer中清除的不干净。

修改后的代码如下:

Code: Select all
#include <iostream>
#include <stdexcept>
using namespace std;

int main(int argc, char **argv)
{
    int ival;
    // cout << "Begin state is: " << cin.rdstate() << endl;
    while (cin >> ival, !cin.eof()) {
        // cout << "Current Enter loop state is: " << cin.rdstate() << endl;

        if (cin.bad()) {
            // no catch so the terminate will be called
            throw runtime_error("IO Stream corrupted");
        }

        if (cin.fail()) {
            cerr << "bad data, try again: ";
            cin.clear();
            // Here cin's error condition state cannot be removed unless
            // we use cin.clear() directly
            // cin.clear(istream::failbit);

            // ignore current read wrong characters otherwise the loop
            // will go infinitely
            cin.ignore(11111111, '\n');
            // cout << "Current state is: " << cin.rdstate() << endl;
            continue;
        }

        // ok, print out this integer
        cout << "Input correct, your number is: " << ival << endl;
    }
}



顺便附上本章的另外一个练习代码,打印文本内容,使用了fstream:

Code: Select all
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;

int main()
{
    ifstream input;
    vector<string> filelist;
    filelist.push_back("read.cc");
    filelist.push_back("fread.cc");
    filelist.push_back("dummy.cc");
    vector<string>::const_iterator it = filelist.begin();

    string s;
    // loop begin
    while (it != filelist.end()) {
        input.open(it->c_str());
        if (!input) {
            cout << "Open file " << *it << " failed, quit..." << endl;
            break;
        }

        cout << "Printing file " << *it << endl;
        while (getline(input, s))
            cout << s << endl;
        input.close();
        input.clear();
        ++it;
    }
}
原文地址:https://www.cnblogs.com/super119/p/1996151.html