忽略空格在C ++中使用getline

时间:2011-02-02 16:22:51

标签: c++ string ignore space getline

嘿,我正在尝试编写一个程序,它将接受来自人的新任务,将其添加到堆栈,能够显示任务,能够将该堆栈保存到文本文件,然后阅读文本文件。当我尝试接受来自用户的输入时,每当你输入一个带有空格的字符串时,问题就出现了,菜单选择只做循环。我需要一种方法来解决这个问题。任何帮助将不胜感激。

// basic file io operations
#include <iostream>
#include <fstream>
#include <stack>
#include <string>
using namespace std;

int main () {
    //Declare the stack
    stack<string> list;

    //Begin the loop for the menu
    string inputLine;
    cout << "Welcome to the to-do list!" << endl;

    //Trying to read the file
    ifstream myfile ("to-do.txt");
    if(myfile.is_open()){

        //read every line of the to-do list and add it to the stack
        while(myfile.good()){
            getline(myfile,inputLine);
            list.push(inputLine);
        }
        myfile.close();
        cout << "File read successfully!" << endl;
    } else {
        cout << "There was no file to load... creating a blank stack." << endl;
    }

    int option;

    //while we dont want to quit
    while(true){
        //display the options for the program
        cout << endl << "What would you like to do?" << endl;
        cout << "1. View the current tasks on the stack." << endl;
        cout << "2. Remove the top task in the stack." << endl;
        cout << "3. Add a new task to the stack." << endl;
        cout << "4. Save the current task to a file." << endl;
        cout << "5. Exit." << endl << endl;

        //get the input from the user
        cin >> option;

        //use the option to do the necessary task
        if(option < 6 && option > 0){
            if(option == 1){
                //create a buffer list to display all
                stack<string> buff = list;
                cout << endl;
                //print out the stack
                while(!buff.empty()){
                    cout << buff.top() << endl;
                    buff.pop();
                }
            }else if (option == 2){
                list.pop();
            }else if (option == 3){
                //make a string to hold the input
                string task;
                cout << endl << "Enter the task that you would like to add:" << endl;
                getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN
                cin.ignore();

                //add the string
                list.push(task);
                cout << endl;
            }else if (option == 4){
                //write the stack to the file
                stack<string> buff = list;
                ofstream myfile ("to-do.txt");
                if (myfile.is_open()){
                    while(!buff.empty()){
                        myfile << buff.top();
                        buff.pop();
                        if(!buff.empty()){
                            myfile << endl;
                        }
                    }
                }
                myfile.close();
            }else{
                cout << "Thank you! And Goodbye!" << endl;
                break;
            }
        } else {
            cout << "Enter a proper number!" << endl;
        }
    }
}

5 个答案:

答案 0 :(得分:3)

您必须在选择选项后立即添加cin.ignore()

//get the input from the user
cin >> option;
cin.ignore();

cin.ignore()之后getline不需要 getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN //cin.ignore();

options

问题出在cin.ignore() - 如果您之后没有调用{{1}},则选项将包含行尾,循环将继续...

我希望这会有所帮助。

答案 1 :(得分:1)

不要这样做:

    while(myfile.good())
    {
        getline(myfile,inputLine);
        list.push(inputLine);
    }

在您尝试通过EOF读取之前,不会设置EOF标志。最后一行读取读取到达(不过去)EOF。因此,如果你输入零,myfile.good()为真,循环就会消失。然后你尝试读取一行,它会失败,但你仍然会推动。

读取文件中所有行的标准方法是:

    while(getline(myfile,inputLine))
    {
        list.push(inputLine);
    }

这样只有在文件包含数据时才会输入循环。

你的另一个问题似乎源于你有:

 std::getline(std::cin,task); // THIS is OK
 std::cin.ignore();           // You are ignoring the next character the user inputs.
                              // This probably means the next command number.
                              // This means that the next read of a number will fail
                              // This means that std::cin will go into a bad state
                              // This means no more input is actually read.

所以只需删除cin.ignore()行,一切都会正常工作。

答案 2 :(得分:1)

而不是使用“&gt;&gt;”直接在您的流上,您可以考虑使用getline,然后尝试从中获取您的选项。是的,它不那么“有效”,但在这种情况下效率通常不是问题。

你知道,问题是用户可以在这里输入一些愚蠢的东西。例如,他们可以输入类似“两个”的东西,点击输入,然后你的程序就会变得合适,因为它乐意继续尝试一遍又一遍地翻译一个空选项。用户唯一可靠的设置方式(以及推荐使用ignore()推荐的方式)就是杀死你的程序。一个表现良好的程序不会以这种方式响应错误的输入。

因此,您最好的选择不是编写脆弱的代码,这些代码可以严重破坏最适度的用户无知/故障,而是编写可以优雅地处理错误情况的代码。你不能希望用户输入一个数字,然后输入换行符。总有一天,你会打得很差。

因此,您有两种选择来阅读您的选项。首先,读取用户的完整行,确保流仍然良好,然后将您获得的字符串转换为流并尝试从中读取整数,确保此其他流仍然良好。第二个选项,尝试读取一个数字,验证流仍然是好的,读取一行并确保流仍然是好的,并且你的字符串是空的(或者如果它不是你的选择就忽略它)。 / p>

答案 3 :(得分:1)

@Vladimir是对的。这是bug背后的机制:

当您输入选项'3'时,实际放入流中的是“3 \ n”。 cin >> option消耗“3”并留下“\ n”。在getline()等待用户输入后,ignore()会消耗“\ n”并呼叫getline()

正如您所看到的,事件序列已经不是您所期望的。

现在,当ignore()等待输入时,你输入你的行。您输入的那一行将是“cin&gt;&gt;选项。

如果您只给它一个符号,ignore()将为您处理它,并且将正确读取选项。但是,如果您为其指定非数字符号,则在尝试读取该选项时,stream将设置failbit。从那时起,您的流将拒绝做任何事情。任何&lt;&lt;或者getline不会在它们应该更改的变量中设置任何新值。你将保持3选项和“”在任务中,紧紧循环。

要做的事情:

  • 始终检查cin.eof(),cin.fail()和cin.bad()。
  • 始终初始化变量并在尽可能最窄的范围内声明它们(在读取之前声明选项= 0)。

答案 4 :(得分:0)

我只是找到了一种方法来破解它,而不是最伟大的但它有效。创建一个字符数组,然后接受数组中的输入,然后将所有内容放入数组中。

char buff[256];
            cout << endl << "Enter the task that you would like to add:" << endl;
            cin >> task;
            task += " ";
            cin.getline(buff, 256);
            for(int i = 1; buff[i] != 0; i++){
                task += buff[i];
            }