- ベストアンサー
for文の中のscanfにスペースが必要な理由を教えてください。
for文の中のscanfにスペースが必要な理由を教えてください。 以下のようなプログラムを作りました。 10 #include <stdio.h> 20 int main() 30 { 40 printf("入力された英字とその次の英字を出力するプログラムである。\n"); 50 char a; 60 for(;;) 70 {scanf(" %c",&a); 80 if(a=='z'||a=='Z') break;else printf("入力された英字は%cで次の英字は%cです。\n",a,a+1);} 90 printf("終了\n"); 100 } というプログラムを作りました。 70の行のscanfの%cの前にスペースを空けないと実行結果が 「入力された英字とその次の英字を出力するプログラムである。 k 入力された英字はkで次の英字はlです。 入力された英字は で英字は(よく分からない文字) です。」 という結果になります。 半角スペースを空けると、正常に実行されて 「入力された英字とその次の英字を出力するプログラムである。 k 入力された英字はkで次の英字はlです。」 となります。半角スペース以外もいろいろ試したのですが、どれも正常に実行されませんでした。 この半角スペースはどういう意味なのでしょうか、また、どういう時にこの半角スペースが必要になるのでしょうか、ぜひ教えてください。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
Cの初心者ないしプログラミングの初心者とお見受けします。 まず、scanf関数は、非常に使い方が難しい関数で、上級者でないと使ってはいけません。もし、入門書にscanfを使う例が載っていたら、その本はまともじゃないので、別の本を探しましょう。 難しさは今回実感しましたね? 元に戻って、なぜ空白が必要かですが、man scanfには、 >ホワイトスペース (スペース、タブ、改行など; isspace(3) 参照) の列。この命令は、入力中の任意の個数のホワイトスペースに一致する。 (「何もなし」にも一致する)。 と書いてあります。 以下の説明では、\n が改行であると知っていることが前提です。 kを入力したときに、kのキーだけでなく、Enterも押しているはずです。 つまり、入力されたのは、"k\n" という文字列なわけです。 これを、scanf(" %c",&a)で読むと、%c が k を読み取り、データとして、\n が残ります。ループの次の繰り返しでは、" %c"の空白が \n に対応して、%c に対応する物が無くなってしまいますので、また次の行を読み取ります。次の行は、z Enterだとすると、"z\n" になります。で、%c に z が対応して読み込まれ、ループが終了。 今度は、scanf("%c",&a)で読む場合。 "k\n" をまず、%c が k を読み取り、\n が残ります。ループの次の繰り返しで、%c が \n に対応して読み取ります。そのため、「入力された英字は」のあとで、\n のために改行されます。また、'\n'+1 が、「よくわからない文字」として表示されたのでしょう。ループの次の繰り返しでようやく "z\n" の z が %c に対応して読み込まれます。 以上の説明を一読して「なるほど」と内容が理解できなければ、scanfを使うのをやめましょう。 この例だと、 案1: for(;;){ a=getchar();/*1文字入力して*/ if(!isalpha(a)) continue; /*英字以外を読み飛ばす*/ if(a=='z'||a=='Z') ..... 案2: char line[1000]; for(;;){ fgets(line,sizeof line,stdin);/*1行入力して*/ a=line[0];/*先頭文字を取り出す*/ if(a=='z'||a=='Z') ..... 案3: char line[1000]; for(;;){ fgets(line,sizeof line,stdin); sscanf(line,"%c",&a); if(a=='z'||a=='Z') .....
その他の回答 (2)
- chie65536(@chie65535)
- ベストアンサー率44% (8802/19961)
ANo.1の >fflush(stdin); >とするのも良い。 は大間違い。 「標準入力がリダイレクトされていると、fflush(stdin);の挙動は不定」となる為「fflush(stdin);はやってはいけない」のです。 多分、fflush(stdin);で入力バッファを捨てようとすると、入力がリダイレクトされた場合に「無限ループしたり、予期せぬ動作をする」でしょう。 LSIC-86のようにユーザーズマニュアルに「標準入力がキーボードになっている場合に限りやっても良い」と記されている場合のみ使用すべきです。 但し「標準入力がリダイレクトされているかどうかは、プログラム自身には判らない」ので、やはりLSIC-86であっても「やってはいけない」のです。 正しく動作させたいのであれば scanf("%c%*[^\n]%*c",&a); のように「1文字読み取って、それ以降の改行文字以外を読み捨てて、さらに改行を読み捨てる」と言う書き方をしないとなりません。
補足
回答ありがとうございました。 いろいろ考えたのですが、初心者なものですから、scanf("%c%*[^\n]%*c",&a);のプログラムの意味がよく分かりません。 ぜひよければもう少し詳しく教えてください。
- f272
- ベストアンサー率46% (8626/18446)
入力の際に押されるリターンキーが入力バッファに残っている。それを読み飛ばすのが半角スペースの役割です。 scanf("%c",&a); としているときに、k[RETURN]とすると%cにkがマッチするけど、次に[RETURN]が%cにマッチするのです。 対処法は scanf(" %c",&a); でもいいけれど scanf("%c",&a); fflush(stdin); とするのも良い。
お礼
早速の回答ありがとうございます。 よくわからない文字というのがアスキーコードで11の文字(ENTERの次の値の文字)でしたので、ENTERが行われて改行されて次の番号の文字が出力されていることが分かりました。
お礼
大変勉強になりました。参考のプログラムはなんとか理解できました。 案1の場合のみ何文字か入力した場合、1文字目以降も残って次のループで実行されていることが分かりました。他の案は1文字目だけを選ぶというプログラムが記載されていて、そういうプログラムがなければ入力した文字は残ることが分かりました。