1

このコードは、ほとんどの場合、ユーザーに1文字の入力を求め、関連するアクションを実行し、ユーザーにReturnキーを押して、繰り返すように求めるという、希望どおりに機能します。ただし、プロンプトで^ D(EOF)と入力すると、無限ループが発生します。std :: cin.clear()を介してエラー状態をクリアし、std :: cin.ignore(...)を呼び出してバッファーをクリアしています。何が無限ループを引き起こしている可能性がありますか?

#include <iostream>
#include <limits>

void wait()
{
    std::cout << std::endl << "press enter to continue.";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin.clear();
    std::cin.get();
}

int main()
{
    char response;

    while (true)
    {
        std::cout << "enter a character at the prompt." << std::endl << "> ";
        std::cin >> response;
        switch (response)
        {
            case 'q':
                exit(0);
                break;
        }
        wait();
    }
}

重要な場合は、これをMacOSXターミナルで実行しています。


更新:ここで私が本当に求めているのは、ユーザーがプロンプトでEOF(^ D)を入力したときに、(a)それを検出し、(b)ユーザーがデータを入力し続けることができるようにストリームをリセットする方法です。

次の例は上記のコードとは異なりますが、^ Dが検出された後にストリームをクリアし、そのストリームからの読み取りを続行するという同じ原則を示しています。

> a
入力したもの:a
> b
入力したもの:b
> ^ D
EOFを入力しました
> c
入力したもの:c
..。
4

7 に答える 7

3

フォーマットされた抽出操作を呼び出した後、ストリームの失敗フラグのいずれかが設定されているかどうかを常に確認する必要があります。この例では、正しく抽出されたresponseかどうかを確認せずに確認しています。response

また、std::endlプロンプト出力で意味をなさない場所で使用しています。std::endlバッファを印刷\nしてからフラッシュしますが、すぐにさらに多くの文字を印刷するため、フラッシュは冗長になります。cincoutは(通常)関連付けられているため、の入力関数を呼び出すと、どのような場合でもフラッシュされるため、プロンプト文字列にaを入れてstd::cin、冗長な余分な演算子を節約することもできます。std::cout\n<<

プロンプトを出力し、入力を取得し、ストリームへの参照を返すプロンプト関数を作成して、通常のストリームからブール型への変換を使用して成功をテストできるようにしてみませんか。

このようにして、whiletrueおよび明示的なブレークを取り除くことができます。

std::istream& prompt_for_input( std::istream& in, std::ostream& out, char& response )
{
    out << "enter a character at the prompt.\n> ";
    in >> response;
    return in;
}

int main()
{
    char response;

    while ( prompt_for_input( std::cin, std::cout, response ) && response != 'q' )
    {
        wait();
    }
}
于 2009-10-21T06:09:24.857 に答える
2

この質問は、標準的な入力にはあまり意味がありません。そのストリームが終了した後、標準入力から何かを読み取るのは困難になります。何らかの方法でそれを再度開く必要がありますが、標準入力を再度開く方法はありません。パイプ、ファイル、または端末に接続されている可能性がありますが、これらすべてに適した動作はありません。

したがって、ターミナルから明示的に読み取ることになります。UN * Xシステムでは、これは/ dev / ttyを読み取り、必要に応じて再度開くことを意味します。これを行う簡単な例を次に示します。ほとんどのエラーチェックは省略されています。

// Warning: UN*X-specific

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    for(unsigned i=0; ; i++) {
        ifstream tty("/dev/tty");
        if (! tty) {
            cerr << "Failed to open TTY" << endl;
            return 2;
        }
        string s;
        while (getline(tty,s))
            cout << i << ": " << s << endl;
    }
    return 0;   // (unreached)
}
于 2009-10-21T09:46:59.130 に答える
0

EOFに遭遇した後、ストリームに多くのことを実行させるには、フラグをクリアする必要があります。

于 2009-10-21T03:11:09.693 に答える
0

えーと、何かが足りないかもしれませんが、ループbreakから外れることはありません。while (true)

// ...
while (true) {
    if (std::cin.eof()) {
        break;
    }
    // ...
}
于 2009-10-21T05:06:56.620 に答える
0

EOFを読み取るときは、ループを終了せずに無視してループバックするだけなので、EOFを継続的に読み取り、継続的にループします。EOFを確認するために何かをしたい場合は、スイッチ内またはその前に処理する必要があります。

おそらく、ユーザーが^ Dでstdinを閉じた後、どこかから入力を読み取りたいですか?その場合、入力を読み取りたい他の場所から読み取るには、cinを閉じてから再度開く必要があります。

于 2009-10-21T05:45:27.040 に答える
0

前述のように、ストリームが悪い状態になっていないことを確認する必要があります。good()を使用するように条件を変更します。EOF以外にストリームが「不良」になる可能性があるため、EOFをチェックするだけではいけません。

while (std::cin.good()) {...
于 2009-10-21T06:33:38.627 に答える
0
while ((std::cout << "Enter a character at the prompt ")
      && (!(std::cin >> response) || response =='q')) {
 std::cout << "Not a valid input";
 std::cin.clear();
 std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

}

于 2009-10-21T09:28:50.677 に答える