Ignore Spaces Using getline in C++
嘿,我正在尝试编写一个程序,该程序将接受人们的新任务,将其添加到堆栈中,能够显示该任务,能够将该堆栈保存到文本文件中,然后读取该文本文件。 当我尝试接受用户的输入时,问题就来了,每当您输入一个带有空格的字符串时,用于选择操作方式的菜单就会循环播放。 我需要一种解决此问题的方法。 任何帮助将不胜感激。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | // 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; } } } |
选择选项后,必须立即添加
1 2 3 | //get the input from the user cin >> option; cin.ignore(); |
并且
1 2 | getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN //cin.ignore(); |
问题出在
我希望这有帮助。
@弗拉基米尔是对的。这是该错误的背后机制:
输入选项" 3"时,实际输入的内容是" 3 n"。
如您所见,事件序列已经不是您期望的。
现在,在ignore()等待输入的同时,键入您的行。您输入的那一行将转到" cin >>"选项。
如果只给它一个符号,ignore()将为您处理它,并且选项将被正确读取。但是,如果为它提供非数字符号,则在尝试读取该选项时,流将设置故障位。从那时起,您的信息流将拒绝执行任何操作。任何<<或getline都不会在应该更改的变量中设置任何新值。您将紧密地选择3个任务和一个任务。
要做的事情:
- 始终检查cin.eof(),cin.fail()和cin.bad()。
- 始终初始化变量,并在尽可能窄的范围内声明它们(在读取之前声明option = 0)。
您可以考虑使用getline,然后尝试从中获取选项,而不是直接在流中使用">>"。是的,它的"效率"较低,但在这种情况下效率通常不是问题。
您会发现,问题在于用户可能在此处输入一些愚蠢的内容。例如,他们可以输入诸如"两个"之类的内容,然后按Enter键,然后您的程序将逐渐适应,因为它很乐意继续尝试一遍又一遍地破译一个空选项。用户唯一的求助方式(以及建议使用
因此,您最好的选择不是编写会因用户的无知/功能最弱而严重崩溃的易碎代码,而是编写可以优雅地处理错误情况的代码。您不能通过希望用户输入数字然后输入换行符来做到这一点。总有一天,您的下注会很差。
因此,您有两个选择来阅读您的选择。首先,从用户那里读一整行,确保流仍然良好,然后将获得的字符串转换为流,并尝试从中读取整数,以确保其他流仍然良好。第二种选择,尝试读取一个数字,验证流仍然是好的,读取一行并确保流仍然是好的,并且您的字符串为空(或者,如果不是,则忽略它,您可以选择)。
不要这样做:
1 2 3 4 5 | while(myfile.good()) { getline(myfile,inputLine); list.push(inputLine); } |
直到尝试读取EOF之后,才会设置EOF标志。最近的全行读取最多读取EOF(不超过位)。因此,如果您的输入为零,则myfile.good()为true,并且会陷入循环。然后,您尝试读取一行,但该行将失败,但是您仍然可以进行推送。
读取文件中所有行的标准方法是:
1 2 3 4 | while(getline(myfile,inputLine)) { list.push(inputLine); } |
这样,仅当文件包含数据时才进入循环。
您的另一个问题似乎源于以下事实:
1 2 3 4 5 6 | 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()行,一切都将起作用。
我只是想出了一种方法来破解它,虽然不是最好的方法,但它确实有效。创建一个字符数组,然后接受数组中的输入,然后将数组中的所有内容放入字符串中。
1 2 3 4 5 6 7 8 | 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]; } |