回答編集履歴

1

追記

2019/05/05 11:16

投稿

otn
otn

スコア84538

test CHANGED
@@ -1,3 +1,41 @@
1
1
  例えば、`123`という入力があったとして、`getchar`で`1`を読んで数字だと判断して`scanf`すると、読み込むのは`23`となり、`1`が欠けてしまいます。
2
2
 
3
3
  そこで`1`をストリームに戻してやると、次の`scanf`で`123`が読めます。
4
+
5
+ #コメントを読んでの追記
6
+
7
+ プログラムで端末から入力するというのがどういうことか理解できていないようなので、少し説明します。
8
+
9
+ (面倒くさいので、複数バイト文字のことは考えず、以下の説明では文字とバイトを同じような意味で使っています)
10
+
11
+
12
+
13
+
14
+
15
+ 端末と、自分で書いたプログラムの間に、ライブラリで実現されているバッファという文字列領域があります。
16
+
17
+ バッファには、端末から文字が入力され、自分で書いたプログラムの`getchar`や`scanf`は、バッファにある文字を変数に代入します。
18
+
19
+ 端末で文字を打って、Enterを押すと、文字が行単位でバッファに追加されます(改行コード付き)。
20
+
21
+ プログラムで`getchar`すると先頭の1バイトをプログラムが得て、バッファからはその1バイトが消えます。
22
+
23
+ プログラムで`scanf`すると、フォーマット文字列に該当するバイト列が(必要なら変換されて)変数に入ります。その分のバイト列はバッファから消えます。
24
+
25
+
26
+
27
+ ここまで理解できたとして、動作を説明します。
28
+
29
+ まず最初に実行される入力関数は、`c = getchar()`のところです。これは、「バッファから1バイトよこせ」という命令ですが、バッファは最初は空です。空のバッファから読もうとした場合は、端末は1行入力状態になり、打った文字列はバッファに入ります。ここで、`123`Enterと打ったとします。この瞬間のバッファは`"123\n"`です。
30
+
31
+ で、`getchar()`は先頭の`'1'`を取って`c`に代入します。この時点のバッファは`"23\n"`です。
32
+
33
+ `isdigit(c)`は真なので、`ungetc(c,stdin)`します。`c`をバッファに返すので、この時点でのバッファは`"123\n"`に戻ります。で、`scanf("%ld",&x)`が実行されますので、`"%ld"`によって文字列`"123"`が`long int`型に変換されて`x`に入ります。この時点のバッファは`"\n"`ですので、次に`getchar()`すると`c`は`'\n'`になり、バッファは`""`つまり空になります。さらに`getchar()`を行うと・・・・最初に戻る。
34
+
35
+
36
+
37
+ 以下補足(蛇足?):
38
+
39
+ 入力が端末じゃなくて、ファイルの場合は、バッファは行単位じゃなくて4096バイトとか8192バイトとかの領域になります。
40
+
41
+ また、端末属性を変更すると、行単位じゃなくてキー1つ単位での入力も可能です。