C言語関係掲示板

過去ログ

No791 scanfの書式指定に"\n"があると

[戻る] [ホームページ]
No.9888

scanfの入力処理について /*初心者*/
投稿者---seren(2003/10/19 20:14:03)


はじめまして。最近c言語をはじめたserenといいます。
scanfの処理についてなんですが、
#include<stdio.h>
void main(void)
{
char a;
while(1)
{
printf("Seach word...");scanf("%c\n",&a);
printf("%c=%d \n",a,a);
}
}
上記のcファイルをC++Builderでコンパイルしてコマンドプロンプトで実行してみたんですが、入力した文字が遅れて処理されてしまいます。
たとえばこんな感じに出力されてしまいます

c:\>exsample
seach key...a    /*aと入力*/
b      /*bと入力(しかしなぜここで入力処理されるか不明!)*/
a=97         /*出力 */
seach key...c    /*cと入力*/
b=98      /*出力 なぜか遅れて表示される!!*/
seach key...d
c=99

なぜこういうことが起こるのかわかりません。
初歩的だと思うのですが、なにとぞよろしくおねがいします。





No.9889

Re:scanfの入力処理について /*初心者*/
投稿者---たか(2003/10/19 22:53:08)


ええとこれは以前に間違えたレスをしたので今回は正しく書いて
みたいと思いますが、はてさて。

scanf("%c\n") という書式文字列は、まず標準入力から一文字読み
取り、ホワイトスペース文字を読み飛ばし、ホワイトスペース文字
以外の文字に出会ったら終了します。

つまり最初に 'a' を入れても '\n' が残っており、これを読み飛ば
したら標準入力が空になるのでまだ入力を待ちます。次に 'b' を
読んだ時点で scanf() は終了し、読み過ぎた 'b' を標準入力に押し
戻します。以後同様です。このようにホワイトスペース文字 ' '、
'\n'、'\t' はscanf()において動作が特殊ですので注意が必要
です。

ではどうすればいいかというと、普通に"%c"で読み、その結果が'\n'
であれば更に読めばよいと思います。(これでいいかな(^_^;))

#include<stdio.h>

int main(void)
{
  char a;
  while(1) {
    printf("Seach word...");
    while (1) {
      scanf("%c",&a);
      if (a != '\n') break;
    }
    printf("%c=%d \n", a, a);
  }
  return 0;
}


No.9890

Re:scanfの入力処理について /*初心者*/
投稿者---nop(2003/10/19 23:57:12)


>ではどうすればいいかというと、普通に"%c"で読み、その結果が'\n'
>であれば更に読めばよいと思います。(これでいいかな(^_^;))

一文字読み込むのに scanf() を使用している事が間違いかと。
getchar() や fgetc() 等を使うべきでしょう。

No.9892

Re:scanfの入力処理について /*初心者*/
投稿者---seren(2003/10/20 01:02:55)


>scanf("%c\n") という書式文字列は、まず標準入力から一文字読み
>取り、ホワイトスペース文字を読み飛ばし、ホワイトスペース文字
>以外の文字に出会ったら終了します。

はぁ〜そういうことだったんですか〜!
詳しい説明どうもです。
なんとなくわかった気がするようなしないような(汗
それで疑問点なのですが、
aを入力した後、
bを入力(このbは標準入力に押し戻される)して、
aが出力されますよね。
このとき読み過ぎた(押し戻された)'b'はどこに格納されているのでしょうか?
たびたびすいません!


No.9905

Re:scanfの入力処理について /*初心者*/
投稿者---たか(2003/10/20 11:22:19)


seren様
>はぁ〜そういうことだったんですか〜!
>詳しい説明どうもです。
>なんとなくわかった気がするようなしないような(汗
>それで疑問点なのですが、
>aを入力した後、
>bを入力(このbは標準入力に押し戻される)して、
>aが出力されますよね。
>このとき読み過ぎた(押し戻された)'b'はどこに格納されているのでしょうか?
>たびたびすいません!

標準入力は普通バッファになっており、押し戻すというと誤解を
招くかもしれませんが、例えばBorland-C++ではBUFSIZは512、現在指して
いる文字は unsigned char *curp となっており、要するに curp を次の
文字に進めなければ押し戻した事になります。ただバッファの最後が
ホワイトスペース文字で終わっていたら期待した動作はさせる事ができ
ませんのでリング・バッファになっている可能性が高いですね。

Visual Studio.Net2003J中のVC++7.1ではBUFSIZは512、現在指している
文字は char *_ptr と処理系によって名前が異なりますが表面上は全く
同じ動作をします。

nop様
>一文字読み込むのに scanf() を使用している事が間違いかと。
>getchar() や fgetc() 等を使うべきでしょう。

おそらく一行単位で読み込むことも想定しておられるのかと思います。
getchar()を使ってしまうとBSが効きませんから。

No.9906

Re:scanfの入力処理について /*初心者*/
投稿者---たか(2003/10/20 11:27:17)


>標準入力は普通バッファになっており、押し戻すというと誤解を
>招くかもしれませんが、例えばBorland-C++ではBUFSIZは512、現在指して
>いる文字は unsigned char *curp となっており、要するに curp を次の
>文字に進めなければ押し戻した事になります。ただバッファの最後が
>ホワイトスペース文字で終わっていたら期待した動作はさせる事ができ
>ませんのでリング・バッファになっている可能性が高いですね。

ちなみにライブラリ関数setvbuf()を使うとBUFSIZの大きさを変える事が
出来、巨大なファイル使用時はパフォーマンスを改善できる事がありま
す。私が実験してみた所ではOSのファイル・キャッシュが効いて、そんな
に大きな差は出ませんでしたが。

No.9907

Re:scanfの入力処理について /*初心者*/
投稿者---たか(2003/10/20 11:31:58)


>要するに curp を次の
>>文字に進めなければ押し戻した事になります。ただバッファの最後が
>>ホワイトスペース文字で終わっていたら期待した動作はさせる事ができ
>>ませんのでリング・バッファになっている可能性が高いですね。

いやまてよ、ungetch()も一文字しか押し戻せないし、やっぱり普通の
バッファでもいいのかも。

No.9909

Re:scanfの入力処理について /*初心者*/
投稿者---nop(2003/10/20 11:39:57)


>おそらく一行単位で読み込むことも想定しておられるのかと思います。

行単位なら gets() や fgets()、
scanf() なら「%s」指定を使うべきかと。

どちらにしろ、「どの様な入力が欲しいのか?」と言う事の考慮不足でしょう。

No.9910

Re:scanfの入力処理について /*初心者*/
投稿者---たか(2003/10/20 11:42:10)


>行単位なら gets() や fgets()、
>scanf() なら「%s」指定を使うべきかと。
>
>どちらにしろ、「どの様な入力が欲しいのか?」と言う事の考慮不足でしょう。

結論を先に言えばそうでしょう。ただscanf()の不可思議な動作に戸惑って
おられるようでしたので一応解説しておきました。

No.9919

Re:scanfの入力処理について /*初心者*/
投稿者---seren(2003/10/20 22:21:13)


>>行単位なら gets() や fgets()、
>>scanf() なら「%s」指定を使うべきかと。
>>
>>どちらにしろ、「どの様な入力が欲しいのか?」と言う事の考慮不足でしょう。
>
>結論を先に言えばそうでしょう。ただscanf()の不可思議な動作に戸惑って
>おられるようでしたので一応解説しておきました。

たかさん、ほんとに参考になりました。
そうですね。僕が読んだ”C言語 入門”って本だとscanfにそんなにページ割いていなくて少し読んだだけで理解したつもりでいたのですが・・・。
そう簡単にいきませんね。
みなさんの説明を聞いていておもったのですが、
もし'\n'の後の文字でscanfが終わるなら、
scanf("\n%c",&a);
とすれば簡単にできるんではないでしょうか・・・?

しかし、この場合2つ以上文字を入力すると変になってしまうかもしれませんが。


No.9920

Re:scanfの入力処理について /*初心者*/
投稿者---たか(2003/10/20 22:43:20)


>もし'\n'の後の文字でscanfが終わるなら、
>scanf("\n%c",&a);
>とすれば簡単にできるんではないでしょうか・・・?
>
>しかし、この場合2つ以上文字を入力すると変になってしまうかもしれませんが。

この場合は先頭にあるホワイトスペース文字を読み飛ばして、ホワイト
スペース文字以外の文字に出会った時点で%cに進みます。もちろん%cで
受けていますから、一度に読める文字は1文字だけです。その他は変わらないような気がします。先頭に"\n"がある効果は "a b c"という文字
列をキーボードから入力してもちゃんと'a' 'b' 'c' と空白をスキップ
してくれることかな?やってみてないのでわかりませんが。

No.9936

Re:scanfの入力処理について /*初心者*/
投稿者---seren(2003/10/22 02:30:52)


そうですか〜。
scanfについてはかなり詳しくなれた気がします。
ありがとうございました!