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

回答編集履歴

6

コメントを受けた追記1

2017/01/14 08:28

投稿

majiponi
majiponi

スコア1722

answer CHANGED
@@ -31,4 +31,30 @@
31
31
  *bufはポインタではなく、char型の変数なので、printf関数が利用不可能な領域にアクセスしてしまい、異常終了します。
32
32
  1文字表示させたいときには、printf("%c", *buf);
33
33
  文字列を表示させたいときには、printf("%s", buf);
34
- というように使い分ける必要があります。
34
+ というように使い分ける必要があります。
35
+
36
+ 3(追記)
37
+ ```C
38
+ char str[8];
39
+ char *ptr = str;
40
+ scanf("%s", &ptr);
41
+ ```
42
+ 最終行が問題です。これはscanf("%s", ptr);とする必要があります。
43
+ 例えば、scanf関数で数値を1つint型の変数iに読み込みたいとしたとき、なぜ
44
+ ```C
45
+ scanf("%d", &i);
46
+ ```
47
+ というように、&を使う必要があるかを説明します。
48
+ C言語では、関数の引数は元の変数や値の「コピー」というルールになってます。
49
+ コピーの方をいくら操作しても、元の変数には何の影響もありません。
50
+ そのため、
51
+ ```C
52
+ scanf("%d", i); /* 本当はダメよ */
53
+ ```
54
+ というように書いたとしても、元の変数は操作できません。
55
+ なので、元の変数の「アドレス」を関数に渡して、そのアドレスの先を操作することで、変数を操作しているのです。
56
+ では、文字列を読み込むときはどうでしょうか。
57
+ ptrは元々ポインタ、すなわちアドレスですよね。
58
+ ptrの指す先の領域を操作すれば、配列の中身を変更できます。
59
+ そして、ptrという「ポインタ変数」を操作する必要はありません。操作するのはその「中身」です。
60
+ なので、%sという文字列読み込みの書式設定の場合だけ例外で、&ptrではなくptrを渡すというルールになっているのです。

5

誤字修正

2017/01/14 08:28

投稿

majiponi
majiponi

スコア1722

answer CHANGED
@@ -1,13 +1,15 @@
1
1
  1(前半) 使用可能な領域のアドレスをポインタにセットしていないから。
2
2
  未初期化のポインタや、ヌルポインタという利用不可能な領域を指すアドレスをセットしたポインタは、使用可能な領域のアドレスをセットしておらず、正しく実行されない。
3
+
3
4
  1(後半) リテラル文字列(二重引用符で囲んだ文字列)は、その内容が格納された読み取り専用領域のアドレスを指す。そのため環境によっては正しく実行されない。
4
5
 
6
+ 2 どちらにも問題がある。
5
- 2 どちらにも問題がある。*bufへの代入は、bufが指す先のchar型への代入を意味する。"456"はchar型のポインタであり、char型ではなく、代入できない。
7
+ *bufへの代入は、bufが指す先のchar型への代入を意味する。"456"はchar型のポインタであり、char型ではなく、代入できない。
6
8
  'Z'はchar型であり、代入可能なのでコンパイルエラーは発生しない。しかし、1(後半)同様、bufは読み取り専用領域を指しているので、環境によっては正しく実行されない。
7
9
 
8
- 3 配列strの「中身が」初期化されておらず、printf関数がどこまで読み込んでいいのか分からず、利用不可能な領域にアクセスしてしまい、異常終了する。
10
+ 3 配列strの「中身が」初期化されておらず、printf関数がどこまで読み込んでいいのか分からず(printf関数はヌル文字にあたるまで読み込み続ける)、利用不可能な領域にアクセスしてしまい、異常終了する。
9
11
 
10
- 4(前半) C言語には、配列をまるごと別の配列にコピーする命令は用意されていないから。配列の名前を書くと、そのアドレスを意味するので、質問者さんのコードは
12
+ 4(前半) C言語には、配列をまるごと別の配列にコピーする命令は用意されていないからです。配列の名前を書くと、そのアドレスを意味するので、質問者さんのコードは
11
13
  ```C
12
14
  1 = 2;
13
15
  ```
@@ -20,13 +22,13 @@
20
22
  s[2] = 'F';
21
23
  s[3] = '¥0';
22
24
  ```
23
- のように、1要素(文字)ずつコピーする必要があ
25
+ のように、1要素(文字)ずつコピーする必要があります
24
- strcpyという関数を使用すればこの面倒は解消され
26
+ (strcpyという関数を使用すればこの面倒は解消されます)
25
27
 
26
28
  4(後半) char型の場合はprintf("%s", *buf);ではダメなようです・・・
27
29
  ということですが、まさにそれが答えです。
28
- printfの書式設定で、sは「引数のポインタの指す先のアドレス」を意味します。
30
+ printfの書式設定で、sは「引数のポインタの指す先のアドレス」にある文字列の表示を意味します。
29
- *bufはポインタではなく、char型の変数なので、printf関数が暴走します。
31
+ *bufはポインタではなく、char型の変数なので、printf関数が利用不可能な領域にアクセスてしい、異常終了します。
30
32
  1文字表示させたいときには、printf("%c", *buf);
31
33
  文字列を表示させたいときには、printf("%s", buf);
32
34
  というように使い分ける必要があります。

4

加筆修正\(最終版\)

2017/01/14 08:09

投稿

majiponi
majiponi

スコア1722

answer CHANGED
@@ -21,4 +21,12 @@
21
21
  s[3] = '¥0';
22
22
  ```
23
23
  のように、1要素(文字)ずつコピーする必要がある。
24
- strcpyという関数を使用すればこの面倒は解消される。
24
+ strcpyという関数を使用すればこの面倒は解消される。
25
+
26
+ 4(後半) char型の場合はprintf("%s", *buf);ではダメなようです・・・
27
+ ということですが、まさにそれが答えです。
28
+ printfの書式設定で、sは「引数のポインタの指す先のアドレス」を意味します。
29
+ *bufはポインタではなく、char型の変数なので、printf関数が暴走します。
30
+ 1文字表示させたいときには、printf("%c", *buf);
31
+ 文字列を表示させたいときには、printf("%s", buf);
32
+ というように使い分ける必要があります。

3

加筆3

2017/01/14 08:05

投稿

majiponi
majiponi

スコア1722

answer CHANGED
@@ -5,4 +5,20 @@
5
5
  2 どちらにも問題がある。*bufへの代入は、bufが指す先のchar型への代入を意味する。"456"はchar型のポインタであり、char型ではなく、代入できない。
6
6
  'Z'はchar型であり、代入可能なのでコンパイルエラーは発生しない。しかし、1(後半)同様、bufは読み取り専用領域を指しているので、環境によっては正しく実行されない。
7
7
 
8
- 3 配列の「中身が」初期化されておらず、printf関数がどこまで読み込んでいいのか分からず、利用不可能な領域にアクセスしてしまい、異常終了する。
8
+ 3 配列strの「中身が」初期化されておらず、printf関数がどこまで読み込んでいいのか分からず、利用不可能な領域にアクセスしてしまい、異常終了する。
9
+
10
+ 4(前半) C言語には、配列をまるごと別の配列にコピーする命令は用意されていないから。配列の名前を書くと、そのアドレスを意味するので、質問者さんのコードは
11
+ ```C
12
+ 1 = 2;
13
+ ```
14
+ と無理矢理代入しているようなものになってしまうのです。
15
+ 面倒でも、
16
+ ```C
17
+ char s[] = "ABC";
18
+ s[0] = 'D';
19
+ s[1] = 'E';
20
+ s[2] = 'F';
21
+ s[3] = '¥0';
22
+ ```
23
+ のように、1要素(文字)ずつコピーする必要がある。
24
+ strcpyという関数を使用すればこの面倒は解消される。

2

加筆2

2017/01/14 07:58

投稿

majiponi
majiponi

スコア1722

answer CHANGED
@@ -1,6 +1,8 @@
1
- 1.(前半) 使用可能な領域のアドレスをポインタにセットしていないから。
1
+ 1(前半) 使用可能な領域のアドレスをポインタにセットしていないから。
2
2
  未初期化のポインタや、ヌルポインタという利用不可能な領域を指すアドレスをセットしたポインタは、使用可能な領域のアドレスをセットしておらず、正しく実行されない。
3
- 1.(後半) リテラル文字列(二重引用符で囲んだ文字列)は、その内容が格納された読み取り専用領域のアドレスを指す。そのため環境によっては正しく実行されない。
3
+ 1(後半) リテラル文字列(二重引用符で囲んだ文字列)は、その内容が格納された読み取り専用領域のアドレスを指す。そのため環境によっては正しく実行されない。
4
4
 
5
- 2. どちらにも問題がある。*bufへの代入は、bufが指す先のchar型への代入を意味する。"456"はchar型のポインタであり、char型ではなく、代入できない。
5
+ 2 どちらにも問題がある。*bufへの代入は、bufが指す先のchar型への代入を意味する。"456"はchar型のポインタであり、char型ではなく、代入できない。
6
- 'Z'はchar型であり、代入可能なのでコンパイルエラーは発生しない。しかし、1.(後半)同様、bufは読み取り専用領域を指しているので、環境によっては正しく実行されない。
6
+ 'Z'はchar型であり、代入可能なのでコンパイルエラーは発生しない。しかし、1(後半)同様、bufは読み取り専用領域を指しているので、環境によっては正しく実行されない。
7
+
8
+ 3 配列の「中身が」初期化されておらず、printf関数がどこまで読み込んでいいのか分からず、利用不可能な領域にアクセスしてしまい、異常終了する。

1

加筆

2017/01/14 07:32

投稿

majiponi
majiponi

スコア1722

answer CHANGED
@@ -1,4 +1,6 @@
1
+ 1.(前半) 使用可能な領域のアドレスをポインタにセットしていないから。
1
- 1. 使用可能な領域をポインタにセットしていないから。未初期化のポインタや、ヌルポインタという利用不可能な領域を指すアドレスをセットしたポインタは、使用可能な領域をセットしておらず、正しく実行されない。
2
+ 未初期化のポインタや、ヌルポインタという利用不可能な領域を指すアドレスをセットしたポインタは、使用可能な領域のアドレスをセットしておらず、正しく実行されない。
3
+ 1.(後半) リテラル文字列(二重引用符で囲んだ文字列)は、その内容が格納された読み取り専用領域のアドレスを指す。そのため環境によっては正しく実行されない。
2
4
 
3
5
  2. どちらにも問題がある。*bufへの代入は、bufが指す先のchar型への代入を意味する。"456"はchar型のポインタであり、char型ではなく、代入できない。
4
- 'Z'はchar型であり、代入可能なのでコンパイルエラーは発生しない。しかし、bufは読み取り専用領域を指しているので、環境によっては正しく実行されない。
6
+ 'Z'はchar型であり、代入可能なのでコンパイルエラーは発生しない。しかし、1.(後半)同様、bufは読み取り専用領域を指しているので、環境によっては正しく実行されない。