web-dev-qa-db-ja.com

scanf()は、バッファーに改行文字を残します

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

_int main(int argc, char *argv[])
{
  int a, b;
  char c1, c2;
  printf("Enter something: ");
  scanf("%d",&a); // line 1
  printf("Enter other something: ");
  scanf("%d", &b); // line 2

  printf("Enter a char: ");
  scanf("%c",&c1); // line 3
  printf("Enter another char: ");
  scanf("%c", &c2); // line 4

  printf("Done"); // line 5

  system("PAUSE");

  return 0;
}
_

Cの本を読むと、著者はscanf()がバッファに改行文字を残したと言っているため、プログラムはユーザーがデータを入力するために4行目で停止せず、新しいc2の行文字。5行目に移動します。

そうですか?

ただし、これはcharデータ型でのみ発生しますか?行1、2、3のようにintデータ型でこの問題は見られなかったので、正しいですか?

63
ipkiss

scanf() 関数は、文字以外の変換を解析する前に空白を自動的に削除します。文字フォーマット(主に_%c_。スキャンセット_%[…]_ —および_%n_)も例外です。空白は削除されません。

オプションの空白をスキップするには、_" %c"_を先頭に空白を付けて使用します。 scanf()形式の文字列には末尾の空白を使用しないでください。

これは、入力ストリームに残っている末尾の空白を行末までも消費しないため、 getchar() または-を使用する場合にも注意してください。 fgets() 同じ入力ストリーム。 _%d_やその他の文字以外の変換の場合と同様に、scanfに空白before変換をスキップさせるだけです。


空白以外の「ディレクティブ」( POSIX scanf用語 を使用する)は、scanf("order = %d", &order);のリテラルテキストのように、変換以外にも空白をスキップしないことに注意してください。リテラルorderは、次に読み込む文字と一致する必要があります。

したがって、前の行から改行をスキップしたいが、固定文字列でのリテラルの一致が必要な場合は、おそらく_" order = %d"_が必要です この質問のように

58

scanf(" %c", &c2);を使用します。これで問題が解決します。

29
Shweta

別のオプション( here から取得した)は、assignment-supression optionを使用して改行を読み取り、破棄することです。これを行うには、%cの間にアスタリスクが付いた文字を読み取る形式を配置します。

scanf("%d%*c",&a); // line 1
scanf("%c%*c",&c1); // line 3

scanfは、次の文字(つまり、改行)を読み取りますが、ポインターには割り当てません。

しかし、最後に、私は2番目になります FAQの最後のオプション

または、要件に応じて、scanf()/ getchar()を忘れて、fgets()を使用してユーザーからテキスト行を取得し、自分で解析することもできます。

2
brandizzi

2番目のgetchar()を呼び出す前にscanf()を使用します。

scanf("%c", &c1);
getchar();  // <== remove newline
scanf("%c", &c2);
0
Jiwon