2011-02-02 353 views
1

嘿,我试图编写一个程序,它将接受来自人员的新任务,将它添加到堆栈,能够显示任务,能够将该堆栈保存到文本文件,然后阅读文本文件。当我试图接受来自用户的输入时,只要输入一个带有空格的字符串,菜单选择刚刚循环的内容,就会出现问题。我需要一种方法来解决这个问题。任何帮助将不胜感激。忽略空格在C++中使用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; 
     } 
    } 
} 
+0

你可以尝试在`cin >> option`之前使用'cin.ignore()`。 – 2011-02-02 16:27:23

+3

您需要对所有输入操作执行错误检查(通过测试流,例如`if(!std :: cin){/ * handle error * /}`,并且您的输入循环不正确:如何编写正确的输入循环,请参阅[这个答案的另一个问题](http://stackoverflow.com/questions/4258887/semantics-of-flags-on-basic-ios/4259111#4259111)。 – 2011-02-02 16:27:40

回答

2

您必须添加cin.ignore()选择选项之后:您getline

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

而且cin.ignore()是没有必要的:

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

的问题是options - 如果你没之后它不会再打cin.ignore(),选项将包含行结束并且循环将继续...

我希望这有助于。

1

不要这样做:

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

的EOF标志没有设置,直到您尝试和阅读过去的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()行,一切都将正常工作。

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

而不是使用“>>”直接在流,你可以考虑使用函数getline,然后试图获取从你的选择。是的,它不那么“高效”,但在这种情况下效率通常不是问题。

你看,问题是用户可以在这里输入一些愚蠢的东西。例如,他们可以输入类似“两节”,按下回车键,然后你的程序是要推销一个合适的,因为它兴高采烈地继续尝试一遍又一遍又一遍又一遍破译一个空的选项。用户的唯一办法,你把它设置方式(以及那些推荐使用的ignore()被推荐的方式)是杀你的程序。一个表现良好的程序不会以这种方式对错误的输入做出响应。

因此,你最好的办法是不要写脆弱的代码,从而严重破坏了最温和的用户无知/故障,而是写的代码,可以从容地处理错误条件。你不能希望用户输入一个数字然后输入一个换行符。总有一天,你会打赌很差。

所以,你有两个选项来阅读你的选择。首先,从用户那里读完整一行,确保数据流仍然正常,然后将字符串转换为流,并尝试从中读取整数,确保其他数据流仍然正常。第二种选择是,尝试读取数字,验证数据流是否正常,读取一行并确保数据流仍然良好,并确保您的字符串为空(或者只是在您选择时忽略它)。

1

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

当你输入选项'3'时,你实际输入的流是“3 \ n”。 cin >> option消耗“3”并留下“\ n”。 getline()消耗“\ n”,并在getline()等待用户输入后致电ignore()。你可以看到,事件序列已经不是你所期望的了。

现在,虽然ignore()正在等待输入,但您可以输入行。如果你只给它一个符号,ignore()会为你处置它,并且选项将被正确读取。但是,如果你给它一个非数字符号,stream将在尝试读取该选项时设置failbit。从这一点开始,你的流将拒绝执行任何操作。任何< <或getline不会在它们应该改变的变量中设置任何新值你会在任务保持3选项“”,在紧密循环

可以做的事:

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