1. ホーム
  2. c++

[解決済み] cinの後にgetline(cin, s)を使用する [重複].

2022-03-06 01:31:21

質問

次のようなプログラムで、ユーザー入力の全行を文字列名にする必要があります。

cout << "Enter the number: ";
int number;
cin >> number;

cout << "Enter names: ";
string names;

getline(cin, names);

を使用すると cin >> number コマンドの前に getline() というコマンドがありますが、(これが問題なのでしょうが)名前を入力することができません。 なぜでしょうか?

というようなことを聞いたことがあります。 cin.clear() しかし、これがどのように機能するのか、なぜこれが必要なのか、まったくわかりません。

どのように解決するのですか?

cout << "Enter the number: ";
int number;
if (cin >> number)
{
    // throw away the rest of the line 
    char c;
    while (cin.get(c) && c != '\n')
        if (!std::isspace(c))
        {
            std::cerr << "ERROR unexpected character '" << c << "' found\n";
            exit(EXIT_FAILURE);
        }
    cout << "Enter names: ";
    string name;
    // keep getting lines until EOF (or "bad" e.g. error reading redirected file)...
    while (getline(cin, name))
        ...use name...
}
else
{
    std::cerr << "ERROR reading number\n";
    exit(EXIT_FAILURE);
}

上のコードでは、このビットが...

    char c;
    while (cin.get(c) && c != '\n')
        if (!std::isspace(c))
        {
            std::cerr << "ERROR unexpected character '" << c << "' found\n";
            exit(EXIT_FAILURE);
        }

...番号の後の入力行の残りは空白のみであることを確認する。

無視を使えばいいのでは?

これではかなり冗長なので ignore の後のストリームで >> x は、次の改行までのコンテンツを破棄するためによく推奨される代替方法ですが、ホワイトスペース以外のコンテンツを破棄し、そうすることでファイル内の破損したデータを見落としてしまう危険性があります。 ファイルの内容が信頼できるかどうか、破損したデータの処理を避けることがどれほど重要かなどに応じて、気にしたりしなかったりすることができます。

では、どのような場合にクリアと無視を使うのでしょうか?

だから std::cin.clear() (そして std::cin.ignore() ) は必要ありませんが、エラー状態を解除するのに便利です。 例えば、ユーザーが有効な数字を入力するチャンスを何度も与えたい場合などです。

int x;
while (std::cout << "Enter a number: " &&
       !(std::cin >> x))
{
    if (std::cin.eof())
    {
        std::cerr << "ERROR unexpected EOF\n";
        exit(EXIT_FAILURE);
    }

    std::cin.clear();  // clear bad/fail/eof flags

    // have to ignore non-numeric character that caused cin >> x to
    // fail or there's no chance of it working next time; for "cin" it's
    // common to remove the entire suspect line and re-prompt the user for
    // input.
    std::cin.ignore(std::numeric_limits<std::streamsize>::max());
}

skipwsなどでもっとシンプルにできないのか?

もう一つのシンプルだが中途半端な代替案として ignore を使用することです。 std::skipws を使えば、行を読む前にいくらでも空白を飛ばすことができます...。

if (std::cin >> number >> std::skipws)
{
    while (getline(std::cin, name))
        ...

...しかし、もし "1E6" のような入力(例えば、ある科学者が 1,000,000 を入力しようとしたが、C++ は浮動小数点数に対してこの記法をサポートしているだけ)があった場合、それを受け付けないため、結局は number に設定します。 1 であり、かつ E6 の最初の値として読み取ります。 name . これとは別に、有効な数字の後に1行以上の空白行があった場合、それらの行は黙って無視されます。