web-dev-qa-db-ja.com

scanf:「%[^ \ n]」は2番目の入力をスキップしますが、「%[^ \ n]」はスキップしません。どうして?

次のコードを検討してください。

#include <stdio.h>

int main (void)
{
  char str1[128], str2[128], str3[128];

  printf ("\nEnter str1: ");
  scanf ("%[^\n]", str1);
  printf ("\nstr1 = %s", str1);

  printf ("\nEnter str2: ");
  scanf ("%[^\n]", str2);
  printf ("\nstr2 = %s", str2);

  printf ("\nEnter str3: ");
  scanf ("%[^\n]", str3);
  printf ("\nstr3 = %s", str3);

  printf ("\n");
  return 0;
}

実行されると、プロンプトに対して最初のscanfのみが停止します。プログラムは、次のscanfで停止しません。ただし、フォーマット文字列が"%[^\n]"から" %[^\n]"に変更された場合(%の前の空白に注意してください)、問題なく動作します。以前の入力バッファからの既存の改行文字は自動的に受け入れられますか?ただし、stdinをフラッシュしてもこれは解決しません。

この原因は何ですか。

28
phoxis

必要なものを読んだら、'\n'文字を「消費」するだけです。次のフォーマットディレクティブを使用します。

"%[^\n]%*c"

改行までをすべて文字列に読み込んでから、何にも割り当てずに1文字(改行)を消費します('*'は「割り当て抑制」です)。

それ以外の場合、改行は後続の"%[^\n]"フォーマットディレクティブの即時終了を待機して入力ストリームに残ります。

フォーマットディレクティブ(" %[^\n]")にスペース文字を追加する際の問題は、スペースがanyホワイトスペースと一致することです。そのため、前の入力の終わりから改行を使用しますが、他の空白(複数の改行を含む)も使用します。

サンプルを更新します。

  char* fmt = "%[^\n]%*c";

  printf ("\nEnter str1: ");
  scanf (fmt, str1);
  printf ("\nstr1 = %s", str1);

  printf ("\nEnter str2: ");
  scanf (fmt, str2);
  printf ("\nstr2 = %s", str2);

  printf ("\nEnter str3: ");
  scanf (fmt, str3);
  printf ("\nstr2 = %s", str3);

  printf ("\n");
43
Michael Burr

scanf()を使用して文字列を読み取る場合、フォーマット文字列(_%[^\n]_)は、_'\n'_ではないすべての文字を読み取るように関数に指示します。入力バッファーに_'\n'_文字が残ります。したがって、_str2_および_str3_を読み取ろうとすると、scanf()は、バッファー内の最初のものが毎回_'\n'_であることを検出し、フォーマット文字列のために、 t入力バッファから削除します。必要なのは、入力バッファーから読み取る時間の間のgetchar()です(多くの場合、scanf()の直後に配置されます)。バッファにはすでに_'\n'_が存在するため、プログラムはgetchar()の入力を待つ必要がないため、ハングしているようには見えません。それを試してみてください。 :)

scanf()修飾子が何をするのかわからない人のために、 http://linux.die.net/man/3/scanf -からの関連する抜粋を以下に示します。

[

指定された受け入れ文字セットの空でない文字シーケンスに一致します。次のポインタはcharへのポインタである必要があり、文字列内のすべての文字と終端のヌルバイトのための十分なスペースが必要です。先頭の空白の通常のスキップは抑制されます。文字列は、特定のセットに含まれる(または含まれない)文字で構成されます。セットは、開き括弧[文字と閉じ括弧]文字の間の文字によって定義されます。オープンブラケットの後の最初の文字がサーカムフレックス(^)である場合、セットはそれらの文字を除外します。セットに閉じ括弧を含めるには、開き括弧またはサーカムフレックスの後の最初の文字にします。他の位置はセットを終了します。ハイフン文字-も特別です。他の2つの文字の間に配置すると、すべての介在文字がセットに追加されます。ハイフンを含めるには、ハイフンを最後の閉じ括弧の前の最後の文字にします。たとえば、[^] 0-9-]は「閉じ括弧、0〜9、およびハイフンを除くすべて」のセットを意味します。文字列は、セット内にない文字(または、曲折アクセント付きの文字)で、またはフィールド幅がなくなったときに終了します。

7
user539810

また、文字列を読み取るには:

scanf("%[^\n]\n", a);

//それは '\ n'に会うまで読むことを意味し、それから '\ n'をゴミ箱に捨てます

:)

3
MLSC

Scanf()関数の後にgetchar()を使用するだけです。

1
Abdus

上記の答えに少しだけ追加します-入力ストリームから特定のパターンを削除したい場合は、0から9までの数字を想定して、バッファをフラッシュするためにgetchar()を使用する必要があります。

scanf("%[^0-9\n]", str1);
while(getchar() != '\n'); // this approach is much better bcz it will
                         // remove any number of left characters in buffer.
scanf("%c", &ch);

したがって、ここでashish019を渡すと、ashishのみがstrにコピーされ、019はバッファーに残されるため、getchar()を複数回必要とすることをクリアします。

0
Ashish Maurya