3

ねえ、私は人々から新しいタスクを受け取り、それをスタックに追加し、タスクを表示し、そのスタックをテキスト ファイルに保存し、テキスト ファイルを読み取るプログラムを作成しようとしています。問題は、ユーザーからの入力を受け入れようとしているときに発生します。スペースを含む文字列を入力すると、何をするかを選択するメニューがループします。これを修正する方法が必要です。どんな助けでも大歓迎です。

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

5 に答える 5

3

cin.ignore()オプションを選択した直後に追加する必要があります。

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

そしてcin.ignore()、あなたの後には必要ありませんgetline:

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

問題は次のとおりですoptions-その後に呼び出さなかっcin.ignore()た場合、オプションには行末が含まれ、ループが続行されます...

これが役立つことを願っています。

于 2011-02-02T17:05:38.253 に答える
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() 行をドロップするだけで、すべてが機能します。

于 2011-02-02T17:05:59.553 に答える
1

ストリームで ">>" を直接使用する代わりに、getline を使用して、そこからオプションを取得しようとすることを検討してください。はい、「効率的」ではありませんが、そのような状況では一般的に効率は問題になりません。

おわかりのように、問題は、ユーザーがここでばかげたことを入力できることです。たとえば、「2」のようなものを入力して Enter を押すと、空のオプションを何度も何度も何度も解読しようとするため、プログラムはうまくいきます。ユーザーがセットアップした方法 (および の使用をignore()推奨しているユーザーが推奨している方法) に対する唯一の手段は、プログラムを強制終了することです。適切に動作するプログラムは、不適切な入力に対してこのように応答しません。

したがって、最善の選択肢は、ごくわずかなユーザーの無知/誤動作で深刻な問題が発生する脆弱なコードを作成するのではなく、エラー状態を適切に処理できるコードを作成することです。ユーザーが数字を入力してから改行を入力することを期待しても、それはできません。いつの日か、あなたは賭けに失敗するでしょう。

したがって、オプションを読み取るには 2 つのオプションがあります。まず、ユーザーから完全な行を読み取り、ストリームがまだ正常であることを確認してから、取得した文字列をストリームに変換し、そこから整数を読み取って、この他のストリームがまだ正常であることを確認します。2 番目のオプションは、数値を読み取って、ストリームがまだ良好であることを確認し、行を読み取って、ストリームがまだ良好であり、文字列が空であることを確認します (そうでない場合は無視することを選択します)。

于 2011-02-02T17:30:37.583 に答える
1

@ウラジミールは正しいです。バグの背後にあるメカニズムは次のとおりです。

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

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

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

シンボルを 1 つだけ指定すると、ignore() がそれを破棄し、オプションが正しく読み取られます。ただし、数値以外の記号を指定すると、ストリームはオプションを読み取ろうとするときに failbit を設定します。その時点から、ストリームは何もすることを拒否します。<< または getline は、変更するはずの変数に新しい値を設定しません。タイトなループで、オプションに 3 を、タスクに "" を保持します。

やる事:

  • cin.eof()、cin.fail()、cin.bad() を常にチェックしてください。
  • 常に変数を初期化し、可能な限り狭いスコープで宣言してください (読み取る直前に option=0 を宣言してください)。
于 2011-02-02T17:43:48.480 に答える
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];
            }
于 2011-02-02T17:19:24.880 に答える