在使用getline处理重定向文件输入后,使用cin进行键盘输入

时间:2015-04-11 10:32:48

标签: c++ cin getline io-redirection istream

我知道,这个问题已被处理了很多次..但我无论如何都无法工作..在这里我贴了一些代码:

#include <sstream>
#include "header.h"
using namespace std;
using namespace header;

int main(){
    string parent, child, line, node;
    int choose = 0;
    tree_ptr tree_inst = new tree;
    cout << "*** Start ***" << endl;    
    while (getline(cin, line, '\n')){
        istringstream line_stream(line);
        line_stream >> parent;
        if (parent.compare("0") == 0) break;
        while (line_stream >> child) {
            if (!tree_inst->insert(parent, child)) {
                cout << "*** ERROR! ***" << endl;
                tree_inst->visit(tree_inst->root);
                cout << "*** End ***" << endl;
                return -1;
            }
        }
    }
    while (true) {
        cin >> choose;  //<== doesn't wait for the input, just loop forever
                        //    on the default statement of the switch...
        switch (choose) {
            ...
        }
    }
}

我已经尝试插入一些cin.sync()cin.clear()cin.ignore().. ..但是没有改变!

1 个答案:

答案 0 :(得分:1)

如果不以某种方式破坏它,第一个getline()循环将永远循环。如果以干净的方式完成,这应该不是问题。实际上我无法重现你的错误。

如何分析错误

因此,原因是cin的不良状态或仍未决的非数字非空间输入。为了帮助您找到答案,我建议您添加一些诊断代码:

cout << "Enter free lines of text or stop to return to the menu:";
while (getline(cin, line, '\n')) {   // This would loop foreved
    if (line == "stop")              // I added this one to exit
        break;                       // but how do you do ?
}
while (true) {                       // I get no problem here
    cout << "Cin status: failed="    // <===Add this simple diagnostic to 
         << cin.fail() << " bad="    //     check the state of the stream 
         << cin.bad() << " eof=" << cin.eof() << endl;  
    cout << "Next char in decimal is:" // <=== Add this to show 
         << cin.peek() << endl;        //      where in the stream you're hanging
    cout << "Choose:";
    cin >> choose;  
    cout << "selected: " << choose << endl;
}

如果您的流状态不干净,尽管有cin.clean(),这是因为您关闭了流或在控制台输入了文件结尾代码( Ctrl + D Ctrl + Z 取决于系统)。

流状态是干净的,但peeked字符不是数字(即十进制代码不在48和57之间),这是将流设置为失败状态的错误输入。

编辑:您的具体案例

查看您提供的诊断(失败= 1,eof = 1),看来在第一个循环之后您已经已经完成了输入的结束。因此您的输入失败,因为没有其他数据可供阅读。您在pastebin上的输入文件确认最后一行是用于退出第一个循环的“0”。

在我们的交流之后,我了解到您实际上已经从命令行重定向输入(例如yourprogramme <yourinput.txt),并且希望您的代码在重定向文件输入到达结尾时切换回键盘输入。不幸的是,这不是它的工作方式。如果您从文件重定向输入,cin将始终引用重定向文件。

为了能够混合文件和键盘输入,您需要使用<fstream>并且更准确地ifstream来读取文件并保留cin以进行键盘输入。

这是一个稍微修改过的代码,它从命令行获取文件名但没有间接(例如yourprogramme yourinput.txt):

...
int main(int argc, char**argv)
{
    if (argc != 2) {     // if called from command line wrong arguments
        cerr << "You must provide the name of the data file as command line argument\n";
        return EXIT_FAILURE;
    }
    ifstream file(argv[1]);     // open the file for reading 
    if (!file) {                // if open failed, end the programme
        cerr << "Could not open "<<argv[1]<<"\n";
        return EXIT_FAILURE;
    }
    string line;                // here your code from before
    int choose = 0;
    cout << "*** Loading "<<argv[1]<< " ***" << endl;
                              // but in the first loop replace cin with file
    while (getline(file, line, '\n')){   
        cout << "Read: " << line<<endl;
        if (line == "0")                // Abridged version;-)
            break;
    }
    file.close();               // File is no longer needed here.  
    while (true) {              // Second loop, unchanged, using cin  
        cout << "Choose (9 to exit):";
        if (!(cin >> choose))   // avoid looping forever if problem on cin
            break;
        cout << "selected: " << choose << endl;
        if (choose == 9)
            break;  
    }
return EXIT_SUCCESS;
}