2011-02-02 29 views
1

ちょっと、人から新しいタスクを受け取り、スタックに追加し、タスクを表示し、そのスタックをテキストファイルに保存できるようにするプログラムを作成しようとしていますテキストファイルを読んでください。この問題は、スペースを含む文字列を入力するたびにユーザーからの入力を受け入れるときに、ループだけを実行するメニューを選択するときに発生します。私はこれを解決する方法が必要です。どんな助けでも大歓迎です。C++でgetlineを使用してスペースを無視する

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

そしてcin.ignore()は必要ありません、あなたの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オプション'の前に 'cin.ignore()'を使うことができます。 –

+3

すべての入力操作についてエラーチェックを実行する必要があります(たとえば、 'if(!std :: cin){/ * handle error * /}'のようなストリームをテストし、入力ループが正しくない場合)入力ループ、[別の質問へのこの回答](http://stackoverflow.com/questions/4258887/semantics-of-flags-on-basic-ios/4259111#4259111)を参照してください。 –

+2

エステートのために:スイッチ/ケース/ default'をブロックは、これらすべての '場合/他の場合/ else' ... – Emmanuel

答えて

2

あなたはオプションが選択された直後cin.ignore()を追加する必要が

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

問題がoptionsである - あなたはdidnの場合それ以降はcin.ignore()にコールしてください。オプションには行末が含まれ、ループは続行されます...

こちらがお役に立てば幸いです。

+0

ユーザーが「2 \ n」と入力するとどうなりますか? 'ignore()'は本当にここで行うべき正しいことですか? –

1

はこれをしないでください。あなたがしようとするとEOFを過ぎて読むまで

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

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()の行を削除し、すべてが動作します:

あなたの他の問題は、あなたが持っているという事実に由来しているようです。

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

の代わりに使用して、「>>」を直接あなたのストリームにあなたはgetl​​ineのを使用して、そこからあなたのオプションを取得しようと考えるかもしれません。はい、それはあまり効率的ではありませんが、このような状況では効率は一般的に問題にはなりません。

あなたが見ている問題は、ユーザーがここに何かばかげたものを入力できることです。たとえば、「2」のようなものを入力してEnterキーを押すと、空のオプションを何度も何度も解読しようとしているので、プログラムはうまくいくでしょう。あなたが設定した方法(そして、ignore()の使用を推奨する方法)は、あなたのプログラムを殺すことだけです。よく振る舞うプログラムは、このようにして悪い入力に応答しません。

このように、あなたの最良の選択肢は、ユーザの無知/誤動作の最も控えめなもので重大に壊れる可能性のある脆いコードを書くのではなく、エラー状態を正常に処理できるコードを書くことです。ユーザーが数字を入力してから改行を入力することはできません。いつかはいつも、あなたはうまくいきません。

あなたのオプションを読むには2つのオプションがあります。最初に、ユーザーからフルラインを読み、ストリームがまだ良好であることを確認してから、ストリームをストリームに変換して整数を読み取ってみて、このストリームがまだ良好であることを確認します。 2番目のオプションでは、数値を読み込み、ストリームがまだ良好であることを確認し、行を読み、ストリームがまだ良好であり、文字列が空であることを確認します(選択しない場合は無視します)。

1

@Vladimirが正しいです。バグの背後にあるメカニズムは次のとおりです。

オプション '3'を入力すると、実際にストリームに入れるのは「3 \ n」です。 cin >> optionは "3"を消費し、 "\ n"を残します。 getline()は「\ n」を消費し、getline()がユーザー入力を待った後にignore()への呼び出しを消費します。

ご覧のとおり、イベントのシーケンスは、すでに期待したものではありません。

今、ignore()が入力を待っている間に、あなたの行を入力します。あなたが入力している行は、 "cin"オプションに行くものです。

ただ1つのシンボルを与えると、ignore()はそれを破棄してオプションを正しく読み込みます。数値以外の記号を指定すると、オプションを読み込もうとしたときにfailbitが設定されます。その時点からストリームは何もしないようにします。< <またはgetl​​ineは変更する変数に新しい値を設定しません。あなたは、タイトなループで、タスクに "" オプションに3を維持します

物事を行う:。

  • を常に)(cin.eofをチェックし、cin.failを( )とcin.bad()です。
  • は常に変数を初期化し、可能な限り狭い範囲で宣言します(読み込む前にオプション= 0を宣言します)。
関連する問題