2011-02-02 176 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)。