【问题标题】:Ignore Spaces Using getline in C++ [duplicate]在 C++ 中使用 getline 忽略空格 [重复]
【发布时间】:2011-02-02 16:22:50
【问题描述】:

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

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

【问题讨论】:

  • 您可以尝试在cin &gt;&gt; option之前使用cin.ignore()
  • 您需要对所有输入操作进行错误检查(通过测试流,例如if (!std::cin) { /* handle error */ },并且您的输入循环不正确:有关如何编写正确的输入循环,请参阅this answer to another question
  • 只是为了美观:switch/case/default 块将比所有这些 if/else if/else 更具可读性...
  • “只是循环”是什么意思?你能添加示例输出捕获吗?
  • 是的 Emmanuel,我从 C# 转到 C++,所以我不知道它们是如何工作的。我只是按照我所知道的去做。

标签: c++ string space getline


【解决方案1】:

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

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

在你的getline 之后不需要cin.ignore()

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

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

我希望这会有所帮助。

【讨论】:

  • 如果用户输入“2\n”怎么办?您认为ignore() 在这里做真的正确吗?
【解决方案2】:

不要这样做:

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

【讨论】:

    【解决方案3】:

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

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

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

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

    【讨论】:

      【解决方案4】:

      @Vladimir 是对的。这是该错误背后的机制:

      当您输入选项“3”时,您实际放入流中的是“3\n”。 cin &gt;&gt; option 消耗“3”并离开“\n”。 getline() 消耗 "\n" 并且您在 getline() 之后对 ignore() 的调用等待用户输入。

      如您所见,事件的顺序已经不是您所期望的。

      现在,在 ignore() 等待输入时,您输入您的行。您正在输入的那一行将转到“cin >> 选项”。

      如果你只给它一个符号,ignore() 会为你处理它,并且选项将被正确读取。但是,如果你给它非数字符号,流将在尝试读取选项时设置失败位。从那时起,您的流将拒绝做任何事情。任何

      要做的事情:

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          猜你喜欢
          • 2021-12-27
          • 2018-09-18
          • 2011-02-07
          • 2023-03-17
          • 2019-03-13
          • 1970-01-01
          • 2016-01-28
          • 1970-01-01
          • 2018-04-24
          相关资源
          最近更新 更多