scanf
関数scanfは、直感的でない挙動をすることがままあり、苦手とする人も多いだろう。 この文書では、scanfに関するエラーを起こさないような記法を学ぶ。
まず覚えてもらいたいのは、標準入力(stdin)というデータ領域である。
キーボードから受け取った入力はまずここに入り、それに対してアクセスする関数がscanf、getcharなどである。
注意しなければならないのは、これらの関数を使った後、標準入力が残ったままになる場合がある
ことである。(代入に失敗したときなど)
関数の紹介
scanf:標準入力から、書式指定子の通りにデータを受け取る。 返り値はintで、代入に成功した変数がいくつあるかを返す。
int num, x;
x = scanf("%d", &num); //代入成功ならx==1
getchar:標準入力の先頭の1文字を受け取る。
char ch;
ch = getchar();
scanfの詳しい使い方
scanfは、一度に複数のデータを受け取ることができる。
int num1, num2;
scanf("%d%d", &num1, &num2);
このようにすると、改行、スペース、タブ文字を区切りとして、2つの整数を受け取ることができる。
scanf("%d,%d", &num1, &num2);
この場合は、カンマ区切り。
書式指定子
scanfの第1引数には文字列が渡されるが、その中でデータの型を示す書式指定子が扱われる。 書式指定子には、以下の様なものが存在する。
- %d -- int
- %lf -- double
- %c -- char
- %s -- 文字列
- %19s -- 文字列を19文字まで
- %[abc] -- 標準入力をabc以外の文字が現れるまで読む
- %[^\n] -- 標準入力を\n(改行)が現れるまで読む
- %*c -- charを1文字読み飛ばす(代入抑止)
改行文字は見えないため、以下の様なミスはよく起こる。
char ch1, ch2;
scanf("%c", &ch1);
scanf("%c", &ch2); //2回めの入力は受け取れない
これは、ch2に標準入力に残った'\n'が代入されるためである。 これを回避するためにはいくつか方法がある。
1.
scanf("%c", &ch1);
scanf(" %c", &ch2); //スペースは改行、スペース、タブ文字に対応する
2.
scanf("%c%*c", &ch1); //代入抑止で'\n'を読み飛ばす
scanf("%c", &ch2);
3.
scanf("%c", &ch1);
getchar(); //改行文字を空読みする
scanf("%c", &ch2);
scanfと文字列
文字列はcharの連続データとして表現され、必ず一番最後の文字は'\0'(数値の0)である。よって、
char str[20];
の様な場合は受け取れる文字数は19文字までとなる。
scanf("%s", str); //20文字以上を代入しようとするとバグ
scanf("%19s", str); //ok
また、この場合でも20文字以上を入力すると標準入力に文字が残る。 標準入力を空にしたい場合は、以下のようにするのが確実である。
while(getchar() != '\n'); //改行文字が表れるまで空読み
標準入力でスペースを使うと、区切り文字として解釈される。
char str[12];
scanf("%11s", str);
//入力:hello world
//str == "hello"
文字列の中でスペースを使いたい場合は、以下のように記述する。
char str[12];
scanf("%11[^\n]", str); //改行以外を受け取る
//入力:hello world
//str == "hello world"
配慮した数値入力
ループを使って数値を入力させることを考える。
while(scanf("%d", &num) != 1); //NG
このscanfは、代入に成功した場合1を返すので、間違った入力をはじくことができる。 しかし、このままでは代入に失敗した場合、標準入力に文字が残り、無限ループに陥る。 これを回避する場合は、先ほどの例を利用し、
while(scanf("%d", &num) != 1)
{
while(getchar() != '\n');
}
と書くとよい。