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

发布于 2024-10-15 17:09:53 字数 3319 浏览 2 评论 0原文

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

// 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;
        }
    }
}

Hey, I'm trying to write a program that will accept new tasks from people, add it to a stack, be able to display the task, be able to save that stack to a text file, and then read the text file. The issue comes when I am trying to accept input from the user, whenever you enter a string with a space in it, the menu to choose what to do just loops. I need a way to fix this. Any help would be greatly appreciated.

// 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;
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

天邊彩虹 2024-10-22 17:09:53

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

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

之后不需要 cin.ignore()

    getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN
        //cin.ignore();

并且在 getline 问题出在 options 中 - 如果您在之后没有调用 cin.ignore() ,选项将包含行尾并且循环将继续...

我希望这有帮助。

You have to add cin.ignore() right after options is chosen:

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

And cin.ignore() is not necessary after your getline:

    getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN
        //cin.ignore();

The problem is in options - if you didn't call cin.ignore() after it, options will contain end of line and loop will continue...

I hope this helps.

扶醉桌前 2024-10-22 17:09:53

不要这样做:

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

在您尝试读取超过 EOF 之前,不会设置 EOF 标志。最后一个整行读取读取到 EOF(不超过该位)。因此,如果您的输入为零,则 myfile.good() 为 true 并且进入循环。然后你尝试读取一行,它会失败,但你仍然执行推送。

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

    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() 行,一切都会正常。

Don't do this:

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

The EOF flag is not set until you try and read past the EOF. The last full line read read up-to (bit not past) the EOF. So if you have have zero input left myfile.good() is true and the loop is enetered. You then try and read a line and it will fail but you still do the push.

The standard way of reading all the lines in a file is:

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

This way the loop is only entered if the file contained data.

Your other problem seems to stem from the fact that you have:

 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.

So just drop the cin.ignore() line and everything will work.

Saygoodbye 2024-10-22 17:09:53

而不是使用“>>”直接在您的流上,您可能会考虑使用 getline,然后尝试从中获取您的选项。是的,它的“效率”较低,但在这种情况下,效率通常不是问题。

您会看到,问题在于用户可能会在这里输入一些愚蠢的内容。例如,他们可以输入“二”之类的内容,然后按回车键,然后您的程序就会陷入困境,因为它会愉快地继续一遍又一遍地尝试破译一个空选项。用户唯一的求助方式就是终止你的程序(以及那些推荐使用ignore()的人所推荐的方式)。一个行为良好的程序不会以这种方式响应错误的输入。

因此,最好的选择不是编写脆弱的代码,因为用户的无知/故障可能会严重崩溃,而是编写可以优雅地处理错误情况的代码。您不能通过希望用户输入数字然后换行来做到这一点。总有一天,你会赌得很差。

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

Instead of using ">>" directly on your stream you might consider using getline and then attempting to fetch your option from that. Yes, it's less "efficient" but efficiency isn't generally an issue in such situations.

You see, the problem is that the user could enter something silly here. For example, they could enter something like "two", hit enter, and then your program is going to pitch a fit as it happily continues trying to decipher an empty option over and over and over and over again. The user's only recourse the way you have it set up (and the way those recommending use of ignore() are recommending) is to kill your program. A well behaved program doesn't respond in this way to bad input.

Thus your best option is not to write brittle code that can seriously break down with the most modest of user ignorance/malfunction, but to write code that can handle error conditions gracefully. You can't do that by hoping the user enters a number and then a newline. Invariably, someday, you'll bet poorly.

So, you have two options to read your option. First, read a full line from the user, make sure the stream is still good, and then turn the string you get into a stream and try to read your integer out of it, making sure this other stream is still good. Second option, attempt to read a number, verify that the stream is still good, read a line and make sure the stream is still good and that your string is empty (or just ignore it if it isn't, your choice).

緦唸λ蓇 2024-10-22 17:09:53

@弗拉基米尔是对的。以下是该错误背后的机制:

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

正如您所看到的,事件的发生顺序已经不是您所期望的了。

现在,当ignore()等待输入时,您可以输入您的行。您输入的那一行将进入“cin >>选项”。

如果您只给它一个符号,ignore()将为您处理它,并且选项将被正确读取。但是,如果您给它一个符号非数字符号,当尝试读取该选项时,流将设置失败位,任何 << 或 getline 都不会在它们应该更改的变量中设置任何新值。您将在紧密循环中保留 3 和 "" 。

要做的事情:

  • 始终检查 cin.eof()、cin.fail() 和 cin.bad()
  • 并声明它们 。在尽可能窄的范围内(在读取之前声明 option=0)。

@Vladimir is right. Here is the mechanism behind the bug:

When you enter option '3', what you actually put into stream is "3\n". cin >> option consumes "3" and leaves "\n". getline() consumes "\n" and your call to ignore() after getline() waits for user input.

As you can see, teh sequence of events is already not what you expected.

Now, while ignore() is waiting for input, you type in your line. That line you're typing is what will go to "cin >> option.

If you just give it one symbol, ignore() will dispose of it for you, and option will be read correctly. However, if you give it non-numeric symbols, stream will set failbit when trying to read the option. From that point on, your stream will refuse to do anything. Any << or getline will not set any new values in the variables they are supposed to change. You'll keep 3 in option and "" in task, in a tight loop.

Things to do:

  • always check cin.eof(), cin.fail() and cin.bad().
  • always initialize your variables and declare them in the narrowest scope possible (declare option=0 right before it's read).
时间海 2024-10-22 17:09:53

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

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];
            }

I just figured out a way to kind of hack through it, not the greatest but it works. Create a character array, and then accept input in the array, and then put everything into the array into the string.

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];
            }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文