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

回答編集履歴

6

コメントに対する回答を追加

2021/02/13 07:57

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -116,4 +116,46 @@
116
116
  これなら理解できますか?
117
117
 
118
118
  p は &str[i]、*p は str[i]、
119
- q は &str[j]、*q は str[j] という関係です。
119
+ q は &str[j]、*q は str[j] という関係です。
120
+
121
+ **追記3**
122
+ > しかし、なぜ*q++ではなく、q++なのでしょうか?
123
+ ++してアドレスをずらしていきながら?:0をを探すのなら*q++ではないのですか?
124
+
125
+ この質問に対して、i++ と a[i++] の例を出して、a[i++] は無意味であり、
126
+ 同様に q++ で済むのに、*q++ と書くのは無意味である、
127
+ と回答しましたが、理解されなかったようですね。
128
+
129
+ ```C
130
+ #include <stdio.h>
131
+
132
+ int main(void)
133
+ {
134
+ int a[4] = { 3, 5, 7, 0 };
135
+ char str[4] = "abc"; // char str[5] = { 'a', 'b', 'c', '\0' }; でも同じ
136
+
137
+ for (int i = 0; a[i] != 0; i++) printf("%d ", a[i]);
138
+ putchar('\n');
139
+ for (int i = 0; a[i] != 0; a[i++]) printf("%d ", a[i]);
140
+ putchar('\n');
141
+ for (int i = 0; a[i] != 0; &a[i++]) printf("%d ", a[i]);
142
+ putchar('\n');
143
+
144
+ for (int i = 0; str[i] != 0; i++) printf("%s ", &str[i]);
145
+ putchar('\n');
146
+ for (int i = 0; str[i] != 0; str[i++]) printf("%s ", &str[i]);
147
+ putchar('\n');
148
+ for (int i = 0; str[i] != 0; &str[i++]) printf("%s ", &str[i]);
149
+ putchar('\n');
150
+
151
+ for (char *p = str; *p != 0; p++) printf("%s ", p);
152
+ putchar('\n');
153
+ for (char *p = str; *p != 0; *p++) printf("%s ", p);
154
+ putchar('\n');
155
+ for (char *p = str; *p != 0; &*p++) printf("%s ", p);
156
+ putchar('\n');
157
+ }
158
+ ```
159
+ i++ や p++ に意味があるのに、それに * や [] や & を付けてもその演算結果を
160
+ 使わないのであれば無意味です。
161
+ わかりませんか?

5

誤字修正(関節参照 → 間接)

2021/02/13 07:57

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -63,7 +63,7 @@
63
63
  p も q もポインタで、str[0] を指しているのです。
64
64
  str[0] は文字列の先頭なので、p と q は文字列を指していると言っていいでしょう。
65
65
 
66
- *q=='?' ですが、* は関節参照演算子なので、*q は q の指している変数になります。
66
+ *q=='?' ですが、* は間接演算子なので、*q は q の指している変数になります。
67
67
  q の値は str[0] のアドレスなので、*q は str[0] です。
68
68
  *q=='?' は str[0]=='?' のことなのです。
69
69
 

4

配列版のコードを追加

2021/02/11 03:03

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -88,4 +88,32 @@
88
88
 
89
89
  for (q = p; !(*q == '?'); q++) を
90
90
  for (q = p; !(*q == '?'); *q++) と書いても同じように動きますが、
91
- そう書く意味はありません。
91
+ そう書く意味はありません。
92
+
93
+ **追記2**
94
+ ポインタを使わずに配列だけで書いてみました。
95
+ 実行手順も実行結果もポインタを使ったものと同じです。
96
+ ```C
97
+ #include <stdio.h>
98
+ #include <string.h>
99
+
100
+ int main(void)
101
+ {
102
+ char str[] = "str == NULL ? \"(NULL)\" : str";
103
+ int i, j;
104
+ int ch;
105
+ i = 0;
106
+ for (;;) {
107
+ for (j = i; !(str[j]=='?' || str[j]==':' || str[j]==0); j++) ;
108
+ ch = str[j];
109
+ str[j] = 0;
110
+ printf("|%s|\n", &str[i]);
111
+ if (ch == 0) break;
112
+ i = j + 1;
113
+ }
114
+ }
115
+ ```
116
+ これなら理解できますか?
117
+
118
+ p は &str[i]、*p は str[i]、
119
+ q は &str[j]、*q は str[j] という関係です。

3

説明の修正

2021/02/02 07:14

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
File without changes

2

説明の修正

2021/02/01 18:12

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -77,7 +77,7 @@
77
77
  *(q++) ということになります。
78
78
  q++ で str[0] のアドレスを持っていた q が str[1] のアドレスを持つようになります。
79
79
  ただし、後置演算子++ の演算結果は 1増えた q の値ではなく、元の値です。
80
- ということは、 q の値は str[0] のアドレスです。
80
+ ということは、 q++ の値は str[0] のアドレスのままです。
81
81
  前置演算子* により *q++ は str[0] になります。
82
82
  この str[0] という変数は、値を参照されることもなく、別の値を代入されること
83
83
  もなく、何の意味もないことになります。

1

コメントの質問への回答を追加

2021/02/01 18:11

投稿

kazuma-s
kazuma-s

スコア8222

answer CHANGED
@@ -36,4 +36,56 @@
36
36
 
37
37
  ch が '?' または ';' だった場合、次に探索する文字列をその次に進めるためです。
38
38
  *q に 0 を代入して文字列を 2つに分割したあとの 2番目の文字列の先頭を
39
- p が指すようにします。
39
+ p が指すようにします。
40
+
41
+ **追記**
42
+ amazon で「苦しんで覚えるC言語」を検索して、「試し読み」で目次を見たら、
43
+ pp.252-354 が「第14章 文字列を扱う方法」と「第15章 ポインタ変数」だと分かりました。
44
+ 説明はとても丁寧で分かりやすく書いてあります。
45
+ これを読んで、q と *q の違いが分からないはずがないと思うのですが、
46
+ まだ分からないのですね。
47
+
48
+ 書名を教えてもらったので、次の質問には答えます。
49
+
50
+ > q=p; はpの値をqに代入します。そして
51
+ !(*q=='?' || *q==':' || *q==0); に進む、
52
+ qに入った文字列を一つとして扱うのではなく、文字列の文字一つ一つの文字のアドレスに含まれる?:0を探すために!(*q=='?' || *q==':' || *q==0);の形にした。
53
+ しかし、なぜ*q++ではなく、q++なのでしょうか?
54
+ ++してアドレスをずらしていきながら?:0をを探すのなら*q++ではないのですか?
55
+
56
+ まず、「q に入った文字列」ですが、
57
+ q はポインタ変数なので、29バイトの文字列は入りません。
58
+ q に入るのは、文字列の先頭アドレスです。
59
+
60
+ p = str; は p = &str[0]; と同じ意味です。
61
+ p には、str[0] のアドレスが入っています。
62
+ q = p を実行すると、q にも str[0] のアドレスが入ります。
63
+ p も q もポインタで、str[0] を指しているのです。
64
+ str[0] は文字列の先頭なので、p と q は文字列を指していると言っていいでしょう。
65
+
66
+ *q=='?' ですが、* は関節参照演算子なので、*q は q の指している変数になります。
67
+ q の値は str[0] のアドレスなので、*q は str[0] です。
68
+ *q=='?' は str[0]=='?' のことなのです。
69
+
70
+ q++ で、q が 1増えます。q の値は str[1] のアドレスになりました。
71
+ 次の *q=='?' は str[1]=='?' のことなのです。
72
+
73
+ これを繰り返すと、str[12] が '?' なので、そこで forループを抜けます。
74
+ q は str[12] を指しています。q には str[12] のアドレスが入っています。
75
+
76
+ *q++ ですが、後置演算子++ のほうが、前置演算子* よりも優先順位が高いので、
77
+ *(q++) ということになります。
78
+ q++ で str[0] のアドレスを持っていた q が str[1] のアドレスを持つようになります。
79
+ ただし、後置演算子++ の演算結果は 1増えた q の値ではなく、元の値です。
80
+ ということは、 q の値は str[0] のアドレスです。
81
+ 前置演算子* により *q++ は str[0] になります。
82
+ この str[0] という変数は、値を参照されることもなく、別の値を代入されること
83
+ もなく、何の意味もないことになります。
84
+
85
+ for (i = 0; a[i] != 0; i++) printf("%d\n", a[i]); を
86
+ for (i = 0; a[i] != 0; a[i++]) printf("%d\n", a[i]); と書いても同じように
87
+ 動きますが、だれもそんな風には書きません。
88
+
89
+ for (q = p; !(*q == '?'); q++) を
90
+ for (q = p; !(*q == '?'); *q++) と書いても同じように動きますが、
91
+ そう書く意味はありません。