1

これら 2 つのコードの違いについて質問があります。

char buffer5[5];
cin.get(buffer5, 5);
cout << buffer5;

cin.get(buffer5, 5);
cout << buffer5;

char buffer4;
while (cin.get(buffer4))
{
    cout << buffer4;
}

コードの最初の部分では、コードは 5 文字を取得し、それを buffer5 に入れます。ただし、Enter キーを押すと、get() を呼び出すときに改行文字がストリームに入れられないため、プログラムは終了し、さらに 5 文字の入力を求めることはありません。

コードの 2 番目の部分では、cin.get() は入力ストリームへの入力を待機するため、ループは終了しません (と思います)。入力ストリームに「Apple」と入力したとしましょう。これにより、5 文字が入力ストリームに入れられ、ループはすべての文字を出力に出力します。ただし、最初のコードとは異なり、入力を続けられるため、2 回入力しても停止しません。

最初のコードではなく 2 番目のコードで端末に連続して文字シーケンスを入力できるのはなぜですか?

4

1 に答える 1

5

まず、「Enter キーを押す」ことは、改行文字 ( ) を入力シーケンスに入力する以外に、IOStream にとって特別な意味はありません\n(テキスト ストリームを使用する場合、プラットフォーム固有の行末シーケンスは単一の改行文字に変換されることに注意してください)。コンソールにデータを入力すると、データは通常、コンソールによって行バッファリングされ、Enter キーを押したときにのみプログラムに転送されます (通常、これはオフにできますが、詳細はプラットフォーム固有であり、この質問には関係ありません)。

s.get(buffer, n)これで、 forの動作std::istream sと、少なくともn文字の配列へのポインターに注意を向けることができますbuffer。これが何をするかの説明は非常に簡単です: を呼び出しますs.get(buffer, n, s.widen('\n'))。について話しているstd::istreamのに、おそらく を変更していないので、単に return を返すstd::localeと想定できます。つまり、呼び出しは がデリミタと呼ばれる場所と同等であり、問​​題はこの関数が何をするかになります。s.widen('\n')'\n's.get(buffer, n, '\n')'\n'

さて、この関数は文字まで抽出し、到達したとき、または次の文字がストリームに残っている区切り文字と同じになったときm = 0 < n? n - 1: 0に停止します (区切り文字を抽出したい場合に使用しました)。null 文字が location に格納されている場合、抽出された文字は と の対応する場所に格納されます。万一、文字を抽出しない場合を設定します。mstd::istream::getline()buffer0 < nbuffer[n - 1]std::ios_base::failbit

OK、これでなぞなぞのすべての要素が整ったはずです: 少なくとも 1 文字で 5 文字未満の文字を入力すると、最初の への呼び出しがget()成功し、バッファ内の次の文字として改行文字が残されました。さらに多くの文字を試みると、get()すぐに区切り文字が見つかり、文字は保存されず、設定によって失敗が示されましたstd::ios_base::failbit。この理論を検証するのは簡単です:

#include <iostream>

int main()
{
    char buffer[5];
    for (int count(0); std::cin; ++count) {
        if (std::cin.get(buffer, 5)) {
            std::cout << "get[" << count << "]='" << buffer << "'\n";
        }
        else {
            std::cout << "get[" << count << "] failed\n";
        }
    }
}

文字を入力しない場合、 への最初の呼び出しはstd::cin.get()失敗します。1 ~ 4 文字を入力すると、最初の呼び出しは成功しますが、2 回目の呼び出しは失敗します。4 文字を超える文字を入力すると、2 番目の呼び出しも成功するなどです。スタックしている可能性のある改行文字に対処するには、いくつかの方法があります。

  1. これが読み取りを停止した理由である場合は、と同じようstd::istream::getline()に動作しますstd::istream::get()が、区切り文字も抽出します。これにより、1 行が複数の読み取りに分割される場合がありますが、これは望ましい場合とそうでない場合があります。
  2. 固定行の長さの制限を回避するには、 (つまり)std::getline()と一緒に使用できます。std::stringstd::getline(std::cin, string)
  3. 成功した後、必要に応じget()て次の文字が改行であるかどうかを確認できstd::istream::peek()ますstd::istream::ignore()

これらのアプローチのどれがニーズを満たすかは、何を達成しようとしているかによって異なります。

于 2012-08-28T19:35:30.407 に答える