teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

説明の追加

2019/07/21 10:31

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -39,4 +39,42 @@
39
39
  ```
40
40
  上手く行くと思います。
41
41
  しかし、%[^] の前のスペースを取り除くとどうなるでしょうか?
42
- その結果に満足ですか?
42
+ その結果に満足ですか?
43
+ ###追加説明
44
+ scanf でググっても、入門ページばかりヒットして、そこには簡単な説明しかないようです。
45
+ man scanf でググると、マニュアルページが出てきて、scanf の仕様の詳細を知ることができるでしょう。
46
+
47
+ %d が何を読み込むかご存知でしょうか?
48
+ ほとんどの人が数字の列だと思っているでしょう。
49
+ 実は、数字の前に + か - の符号があってもいいのです。
50
+ さらに、0個以上の空白があってもいいのです。
51
+ 空白というのは、スペース、タブ、改行などです。
52
+
53
+ %d に限らず、%f でも %s でもほとんどすべての変換指定が
54
+ 0個以上の空白を読み飛ばしてから指定の文字列を読み取り値に変換します。
55
+ 例外は %c と %[ です。
56
+ この 2つの変換指定は先頭の空白の読み飛ばしを行いません。
57
+
58
+ scanf の書式には、0個以上の指令が含まれます。
59
+ 指令には、次の 3種類があります。
60
+ (1) 空白(スペース、タブ、改行など。isspace参照)、
61
+ (2) %でも空白でもない通常の文字、
62
+ (3) %で始まる変換指定。
63
+
64
+ "30,male\n" という入力が、"%d,%s" で読み込めるのは
65
+ 変換指定 "%d" が "30"を読み込み、
66
+ 通常の文字 "," が "," を読み飛ばし、
67
+ 変換指定 "%s" が "male" を読み込むからです。
68
+
69
+ "\n" は入力バッファに残されています。
70
+ 次の行の入力の書式にはこれを読み飛ばす指令がないといけません。
71
+
72
+ "%s" なら、空白(改行)を読み飛ばしますから問題ありません。
73
+ "%[" なら、空白(改行)を読み飛ばさないので問題です。
74
+ そこで、指令の(1) のスペースをつけて明示的に空白(改行)を読み飛ばします。
75
+
76
+ scanf は仕様が複雑なため、ほとんどの人がその詳細を理解せず、いい加減に
77
+ 使用してトラブルに巻き込まれ、使わないほうが良いと結論付けています。
78
+
79
+ scanf は、「指定した書式に従う入力しか読み込まない」という素直で頑固な
80
+ 入力関数なのです。

1

説明の追加

2019/07/21 10:31

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -3,4 +3,40 @@
3
3
  これがないと、2行以上読み込む場合におかしなことになります。
4
4
  なぜそうなるのか自分で確かめてください。
5
5
  自分で考えて調べて、それでも分からない場合は質問してください。
6
- 詳しく説明します。
6
+ 詳しく説明します。
7
+ ###追記
8
+ > これがないと、2行以上読み込む場合におかしなことになります。
9
+
10
+ この意味がうまく伝わらなかったようなので、説明を追加します。
11
+ ```C
12
+ #include <stdio.h>
13
+
14
+ typedef struct { char name[10]; int age; char gender[10]; } student;
15
+
16
+ int input(student *data)
17
+ {
18
+ printf("input name,age,gender :");
19
+ return scanf(" %[^,],%d,%s", data->name, &data->age, data->gender) == 3;
20
+ }
21
+
22
+ void output(const student *data)
23
+ {
24
+ printf("name = %s, age = %d, gender = %s\n", data->name, data->age, data->gender);
25
+ }
26
+
27
+ int main(void)
28
+ {
29
+ student data[100];
30
+ for (int i = 0; i < 100 && input(&data[i]); i++)
31
+ output(&data[i]);
32
+ }
33
+ ```
34
+ このプログラムを実行して、次の入力を与えてみてください。
35
+ ```
36
+ taro,30,male
37
+ aya,18,female
38
+ hirosi,23,male
39
+ ```
40
+ 上手く行くと思います。
41
+ しかし、%[^] の前のスペースを取り除くとどうなるでしょうか?
42
+ その結果に満足ですか?