• ベストアンサー

なぜ2回表示されるのでしょうか?

このたび、諸事情によりC言語から再入門中です。 VisualC++2005を使っています。 do~while文を用いて、キーボードから'q'が入力されるまで、 画面に"qを入力して下さい"と表示し続けるプログラムを 作成してみました。 #define _CRT_SECURE_NO_DEPRECATE 1 #include <stdio.h> // キーボードから'q'が入力されるまで、画面に"qを入力して下さい"と表示し続けるプログラム int main(void) { char c = '\0'; do { printf("qを入力して下さい\n"); scanf("%c", &c); if (c == 'q') { break; } }while(1); return 0; } 実行してみると、以下のように動作します。 1."qを入力して下さい\n"が表示される 2.'a'を入力してEnter 3."qを入力して下さい\n"が2行表示される おそらく、2の際に、'a'と'\0'を受け取ってしまい、 それが3の原因になっている気がします。 でも、scanfで"%c"を指定しているのに、こんなこと あり得るのでしょうか? 仮にソースに誤りが無かった場合、 たかが演習とはいえ自分としてはこの動作を回避したいのですが、 どういった対策があるのでしょうか? 初歩的な質問で申し訳ありませんが、よろしくお願いしますm(__)m

noname#32133
noname#32133

質問者が選んだベストアンサー

  • ベストアンサー
  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.2

この現象は有名ですね。 これはscanfに「指定した文字だけを読み込む」という 仕様があるためです。 aをコンソールで入力すると "a\n"   という文字列が入力ストリームの中に入ります。 (ダブルクォートは含まない) scanf("%c", &c);とすると、%cにマッチする'a'が まず読み込まれますが、'\n'は読み込まれずに 入力ストリームに残ったままとなります。 このため、ループして2回目にコールされた scanf("%c", &c);で'\n'が読み込まれ 3回目で入力ストリームが空なので、 また入力を待ちます。 #include <stdio.h> int main(void) {  char c = '\0';  do{   printf("qを入力して下さい\n");   scanf("%c%*[^\n]%*c", &c);   if (c == 'q'){    break;   }  }while(1);  return 0; }

noname#32133
質問者

お礼

aris-wizさんありがとうございます。 有名な現象なんですねー、全然知らなかったです。 仕事でVisualC++やらC#使ってるのにちょっと恥ずかしいです^_^; 実は、上記言語を使って開発はなぜかできちゃってるけど、 (それも危険な話ですよね・・・) 自分で理解してないことに危機感を感じる場面がありまして。 今のうちに手を打たなければと思って、自学で再入門している次第です。 aris-wizさんが回答された内容を踏まえて、 「新ANSI C言語辞典」でscanf関数を調べてみました。 処理内容はaris-wizさんが書かれていたソースと同じですが、 1.1文字入力 2.Enterの直前まで切り捨てる 3.Enterを切り捨てる の3つの処理に分かれていて、それを見てようやく理解できました^_^; 正規表現も覚えきれてないことに気づいて少々凹み気味です。 でも、以前に一緒に仕事した方に言われた 「気づいたときに一歩を踏み出しているんですよ」 という言葉を思い出してモチベーション上がったところです。

その他の回答 (1)

  • php504
  • ベストアンサー率42% (926/2160)
回答No.1

入力のときに'a'と'Enter'の2回キーを押しますよね 'a'と'\0'ではなくて'a'と'\n'(改行)を受け取るためにそうなります。 scanf("%c", &c); を scanf(" %c", &c); にしたらとりあえずは回避されると思います。

noname#32133
質問者

お礼

php504さんありがとうございます。 'a'と'\0'ではなくて'a'と'\n'(改行)を受け取るのですね。

関連するQ&A

  • 表示がうまくいかない…

    キーボードから文字を入力させて,入力させた文字を画面に表示させるという プログラムを作っています(ある文字を打つとプログラムを終了)。 プログラムを実行すると 「文字を入力してください」   (文字を入力すると) 「あなたが入力した文字は○です」 「文字を入力してください」 (なぜか文字を入力する暇もなく下の行に) 「文字を入力してください」 (ここではまた文字入力ができる) という風になります。 2回目の「文字を入力してください」がうまくいきません。 使用している関数はdo-while,scanf,printfのみです。 よろしくお願いします。

  • C言語の非標準コンソール関数getch()について

    こんにちは。 あるプログラムを作っていると、次のような問題が起きてしまいました。 簡単なプログラムを例にして、説明したいと思います。 #include<stdio.h> #include<conio.h> #include<ctype.h> void main(void) { char ch; int i; do{ ch=getch(); putchar(toupper(ch)); }while(ch!='q'); printf("\n"); scanf("%d",&i); } これはgetch()関数を使い入力された文字を大文字にして画面上に出力するものです。(qが入力されるまで) その後に、意味はありませんが変数iに整数を入力して終了する。 ここで、問題になってくるのがこのプログラムを実行して、abcdefqと入力していくと、画面上にはABCDEFQと表示されます。そして、qが入力されたことでdo文が終了して改行が行われます。次にscanfによりいったん入力待ちになります。 この時、まだ、なにも入力していないにも関わらず、最後にgetchにより入力したqが表示されてしまいます。 qを消してscanfの入力をすればいいのですが、この問題を何とか解決したと思い質問しました。 scanfの後にgetchar()を使うときはscanf入力時の'\n'に注意が必要だということはわかるのですが、上に述べたような問題はこれに似ているのでしょうか? 参考書をみたり自分でもいろいろ試してみたのですがどうもうまくいきません。 どなたか、解決策を知っていたら是非教えて下さい。 できれば、getch()とscanfがどのように作用してこのようなことが起きてしまっているのか説明して頂けたら幸いです。 お手数ですが、みなさま、よろしくお願いいたします。

  • scanfが2回使えない・・・?;

    scanfが使えなくて困っています。どなたか教えていただけないでしょうか(>_< 現在scanfが2つあるプログラムを作っています。 scanfのあるプログラムを実行すると入力待ち画面になりますよね。以下のプログラムを実行すると 1回目のscanfは入力待ちになるのですが2回目は入力待ちにならずに 最後まで行ってしまいます・・。 void main(){ int b; char d, names[20]; printf("名前入力\n"); scanf("%s", &names); printf("1文字キー入力\n"); scanf("%c", &d); printf("\n名前は %s : キーは %c です。\n", names, d); } 実行結果 -------------------------------------- 名前入力 dra2jp 1文字キー入力 名前は dra2jp : キーは です。 -------------------------------------- 名前入力のところは入力待ちになるのですがキー入力ができずに一気に最後までいってしまい、 つまり2回入力待ちにならなければならないのに1回の入力でプログラムが終了してしまいます。 どこが間違っているのでしょうか(>_< どなたかご指導お願いします:;

  • while文の作成について

    キーボードに整数を打ち込み、0を打ち込むと終了し、その合計を出すプログラムを以下のように作りました。 #include<stadio.h> int main(void){ int num=0 int sum=0 printf("整数を入力"\n"); do{ scanf("%d",&num); sum +=num; }while(num); printf("合計は%dです。\n",sum); returen 0; } 次に負の値が入力されるまで整数を読み込み続け、その合計をを求めるプログラムを作りたいのですが、whileのところを }while(num>=0); としてみたのですが、うまくいきません。また分かり易くするため、入力した整数の個数も表示できるようにしたいです。どうすればよいでしょうか。詳しい方、教えてください。

  • 関数の値(scanf)

    初心者なもので、言葉の使い方を間違っていたら申し訳ありません。いいたいことが伝わればよいのですが…。 scanfに関して疑問に思ったことがあります。経験的なことなので、正しいかわからないです。次の(1)と(2)から(3)のことが正しいか教えてください。 (1) int a; do{ printf("整数を入力してください\n"); }while(scanf("%d",&a) ==0); printf("入力した数は、%dです",a) このとき、「(いかなる整数)+(ENTER)」を入力しても、do~whileのループを抜け出す。 (2)また、上のプログラムで、継続条件式の中身を  … }while(scanf("%d",&a)!=0);  … とすると、「(いかなる整数)+(ENTER)」を入力してもループが抜け出せない。 (3)したがって(1)と(2)から、scanf()は入力するだけで、値を真(1)を返す。

  • 複合プログラム についてです。

    複合プログラム 下図のような動作を行うLZ77符号の復号プログラムの???にどのようなプログラムを入力すれば完成しますか? #include<stdio.h> char Str[17]="AAAAAAAA"; ??? void main(void){ int p, max, position; char moji; while(1){ scanf("%d %d %c", &position, &max, &moji); ??? ?? 実行結果は以下のようになります。 キーボード入力→0 1 B 画面出力→AB キーボード入力→ 0 0 C 画面出力→C キーボード入力→5 3 B 画面出力→ABCB キーボード入力→3 2 C 画面出力→CAC キーボード入力→5 4 B 画面出力→CACCB キーボード入力→-1 0 A 続行するには何かキーを押して下さい・・・ となりますので、 上に書いてあるプログラムの足りない部分を教えて下さい。 よろしくお願いします。

  • BM法(ボイヤームーア法)について

    BM法(ボイヤームーア法)について VisualC++にて、BM法のプログラムを作りたいと思いましたが、書き方が、わかりません。 概要を下記にまとめますので、どなたか、作ってみてくれませんか? お早めにお願いします!! 1.scanf(入力関数(これ以外でも可))にて、テキスト(検索される文字列)を入力する。 2.上記にて、パターン(比較する文字列)を入力する。 3.BM法にて、1.と2.を比べて、あったら、"○○文字目にありました。\n\n" 4.続けて検索するか、しないか(While(これ以外でも可))を入力してもらう。(C(大文字か、小文字のC)を入力したら、続ける。E(大文字か、小文字のE)を入力したら、終了する))) 上記のような、プログラム作りは可能でしょうか? 可能なら、作ってみてくれませんか? 不可能なら、どこがダメか、どうしたらよいか、を踏まえ、サンプル的なプログラムを作ってみてくれませんか? お願いします。

  • while for の使い方?

    for文 を使って,キーボードから1以上10以下の整数を入力した後,その整数から30までの和を求めて画面に表示するプログラム prog5.c を作って下さい.ただし,while文を使って,キーボードから入力された整数が1以上10以下になるようにしてから,for文を実行すること. という問題で、次のように書いたら、エラーが発生しました。解説お願いします。 #include<stdio.h> main() { int i, n, sum=0; scanf("%d",&i); while(1<=i<= 10){ for(n=i, n<=30, n++){ sum+=sum+n; } } } エラー prog5.c: In function ‘main’: prog5.c:13: error: expected ‘;’ before ‘)’ token prog5.c:13: error: expected expression before ‘)’ token   

  • C言語について。

    今、C言語に関する問題をやっているんですが、いまいちわかりません。 その問題というのは↓ ≪問題5 (繰り返し) 例題をもとに、次のような九九の表を出力するプログラムを作成しなさい。  1 2 3 4  5  6  7  8  9  2 4 6 8 10 12 14 16 18  ~(略)                                               ≫ という問題です。それで、その例題というのは↓ ≪例題4 (for文、do while文)  次のプログラムは、入力された整数を一辺とする正方形を出力するプログラムである。動作確認をしなさい。  4       (←入力)  ****  (←出力)  ****  ****  **** /* 正方形 */ #include <stdio.h> void main() {     int hen, i, j;     do{        printf("数字(2~9)を入力してください : ");        scanf("%d", &hen);        if( hen < 2 || hen > 9 )           printf("入力エラーです!\n");     }while( hen < 2 || hen > 9);     for( i = 1 ; i <= hen ; i++)     {         for( j = 1 ; j <= hen ; j++)           printf("*");         putchar('\n');    } }  ≫ ≪例題5 (for文、do while文) 次のプログラムは、入力された整数を一辺とする二等辺三角形を出力するプログラムである。動作確認しなさい。  4      (←入力)  *     (←出力)  **  ***  **** /* 二等辺三角形 */ #include <stdio.h> void main() {     int hen, i, j;     do{        printf("数字(2~9)を入力してください : ");        scanf("%d", &hen);        if( hen < 2 || hen > 9 )           printf("入力エラーです!\n");     }while( hen < 2 || hen > 9 );     for( i = 1 ; i <= hen ; i++ )     {            for( j = 1 ; j <= i ; j++ )              printf("*");          putchar('\n');     } }  ≫ 以上の二つが例題です。 わかりづらかったらすみませんm(_ _)m わかる方(問題5を)教えてくださるとありがたいです。

  • 九九を表示させるプログラム

    掛け算の九九、和の九九、差の九九を表示するプログラムを組むという問題ですが、コメント文の所のプログラムが分からないので教えてください。プログラムは以下の通りに与えられています。 #include<stdio.h> main(){ int x,y,z; int yn,op; do{ do{ printf("[*(1),+(2),-(3)]"); scanf("%d",&op); }while( 1 > op || op > 3 ); //ここに、九九を計算し表示するプログラムを入れる //変数opの値が1なら、掛け算の九九 //変数opの値が2なら、和の九九 //変数opの値が3なら、差の九九 を計算し表示 do{ printf("Continue[1/0]?"); scanf("%d",&yn); }while( 0 > yn || 1 < yn ); }while( yn == 1 ); }