web-dev-qa-db-ja.com

Cの入力バッファをクリアする方法は?

私は次のプログラムを持っています:

int main(int argc, char *argv[])
{
  char ch1, ch2;
  printf("Input the first character:"); // Line 1
  scanf("%c", &ch1); 
  printf("Input the second character:"); // Line 2
  ch2 = getchar();

  printf("ch1=%c, ASCII code = %d\n", ch1, ch1);
  printf("ch2=%c, ASCII code = %d\n", ch2, ch2);

  system("PAUSE");  
  return 0;
}

上記のコードの作成者が説明したように、プログラムは1行目でユーザーがEnterキーを押すと、入力バッファー2の文字Enter key (ASCII code 13)および\n (ASCII code 10)のままになるため、プログラムは正常に動作しません。したがって、2行目では\nを読み取り、ユーザーが文字を入力するのを待ちません。

わかった、これだ。しかし、私の最初の質問は、2番目のgetchar()ch2 = getchar();)が\n文字ではなくEnter key (13)を読み取らないのはなぜですか?

次に、著者はそのような問題を解決する2つの方法を提案しました。

  1. fflush()を使用します

  2. 次のような関数を書きます。

    void
    clear (void)
    {    
      while ( getchar() != '\n' );
    }
    

このコードは実際に機能しました。しかし、それがどのように機能するかを自分で説明することはできませんか? whileステートメントではgetchar() != '\n'を使用しているため、それは'\n'以外の任意の1文字を読み取ることを意味しますか?もしそうなら、入力バッファにはまだ'\n'文字が残っていますか?

67
ipkiss

行1でユーザーがEnterキーを押すと、入力キー2(Enterキー(ASCIIコード13)および\ n(ASCIIコード10))が入力されるため、プログラムは正常に動作しません。したがって、2行目では\ nが読み取られ、ユーザーが文字を入力するまで待機しません。

2行目に表示される動作は正しいですが、それはまったく正しい説明ではありません。テキストモードストリームの場合、プラットフォームで使用される行末(キャリッジリターン(0x0D)+ラインフィード(0x0A)、ベアCR、ベアLF)は関係ありません。 Cランタイムライブラリがそれを処理します。プログラムでは、改行に対して'\n'のみが表示されます。

文字を入力してEnterキーを押すと、その入力文字は1行目で読み取られ、'\n'は2行目で読み取られます。 私はscanf %cを使用して読み取りますY/N応答ですが、後で入力がスキップされます。 comp.lang.c FAQから。

提案されたソリューションについては、(再びcomp.lang.c FAQから)を参照してください:

基本的に、唯一のポータブルなアプローチはそうすることです:

int c;
while ((c = getchar()) != '\n' && c != EOF) { }

getchar() != '\n'ループが機能するのは、getchar()を呼び出すと、返された文字がすでに入力ストリームから削除されているためです。

また、scanfの使用を完全に禁止する義務があると感じています: なぜscanfを使用しないと言うのですか?代わりに何を使用すればよいですか?

74
jamesdlin

あなたはそれを(また)この方法で行うことができます:

fseek(stdin,0,SEEK_END);
37
Ramy Al Zuhouri

台詞:

int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
    ;

改行('\n')の前の文字のみを読み取りません。ストリーム内のすべての文字を読み取ります(そしてそれらを破棄します)最大でそれを含む次の改行(またはEOFに遭遇します)。テストが真であるためには、最初に改行を読む必要があります。そのため、ループが停止すると、改行は最後に読み取られた文字でしたが、読み取られました。

キャリッジリターンではなくラインフィードを読み取る理由は、システムがリターンをラインフィードに変換したためです。 Enterキーを押すと、行の終わりを示しますが、システムの通常の行末マーカーであるため、ストリームには代わりに改行が含まれます。プラットフォームに依存する場合があります。

また、入力ストリームでfflush()を使用しても、すべてのプラットフォームで機能するわけではありません。たとえば、一般的にLinuxでは機能しません。

11
Dmitri

すでに部分的に読み込もうとした行の最後までクリアするポータブルな方法は次のとおりです。

int c;

while ( (c = getchar()) != '\n' && c != EOF ) { }

これは、ファイルの終わりを知らせる\nを取得するまで文字を読み取り、破棄します。また、入力ストリームが行の終わりまでに閉じられた場合にEOFに対してチェックします。 cの型は、値intを保持できるようにするためにEOF(またはそれ以上)でなければなりません。

現在の行の後に他の行があるかどうかを調べるポータブルな方法はありません(ない場合、getcharは入力をブロックします)。

10
M.M

しかし、それがどのように機能するかを自分で説明することはできませんか? whileステートメントではgetchar() != '\n'を使用するため、'\n' ??もしそうなら、入力バッファにはまだ'\n'文字が残っていますか???私は何かを誤解していますか?

あなたが気付かないかもしれないことは、比較が起こることですaftergetchar()は入力バッファから文字を削除します。したがって、'\n'に到達すると、それが消費され、thenループから抜け出します。

8
zwol

あなたが試すことができます

scanf("%c%*c", &ch1);

ここで、%* cは改行を受け入れ、無視します

未定義の動作を呼び出すfflush(stdin)の代わりにもう1つのメソッドを記述できます。

while((getchar())!='\n');

whileループの後のセミコロンを忘れないでください

6
kapil

まだ言及されていない別の解決策は以下を使用することです:rewind(stdin);

4
James Blue
unsigned char a=0;
if(kbhit()){
    a=getch();
    while(kbhit())
        getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;

-または-

多分使用する_getch_nolock() .. ???

1

ソリューションを実装しようとして問題が発生しました

while ((c = getchar()) != '\n' && c != EOF) { }

同じ問題を抱えている可能性がある人のために、少し調整した「コードB」を投稿します。

問題は、プログラムがエンター文字とは別に「\ n」文字をキャッチし続けることでした。ここに問題を与えたコードがあります。

コードA

int y;

printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
   continue;
}
printf("\n%c\n", toupper(y));

そして調整は、whileループ内の条件が評価される直前に(n-1)文字を「キャッチ」することでした。コードは次のとおりです。

コードB

int y, x;

printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
   x = y;
}
printf("\n%c\n", toupper(x));

可能な説明は、whileループが中断するために、変数yに値 '\ n'を割り当てる必要があるため、最後に割り当てられた値になるということです。

説明で何かを見逃した場合は、コードAまたはコードBを教えてください。

それが誰かを助けることを願って

1
antadlp

短く、移植性があり、stdio.hで宣言されています

stdin = freopen(NULL,"r",stdin);

次のような既知の行のように、stdinにフラッシュするものが何もない場合、無限ループにハングアップしません。

while ((c = getchar()) != '\n' && c != EOF) { }

少し高価なので、繰り返しバッファをクリアする必要があるプログラムでは使用しないでください。

同僚から盗んだ:)

0
Jason Enochs