ページ 1 / 1
大学生
Posted: 2015年8月03日(月) 14:25
by ポインタと配列
Cで以下のプログラムを実行しようとしたのですが (1)の所がSegmentation fault: 11 と表示されてしまい、うまく値を表示してくれません。str = a = *b というのは理解できたのですが、 str[2] = a[2] = *b[2] というのはやはり間違いなのでしょうか??
ポインタのポインタが理解できていないのでおそらくこのようなことになっていると思うのですが、いまいち調べても理解できません。解決して下さる方がいましたら、教えてください。よろしくお願いしますm(_ _)m
コード:
int main(){
char str[]="kitty on your lap";
char *a;
char **b;
a = str;
b = &a;
printf("%s\n", str);
printf("%s\n", a);
printf("%s\n", *b);
putchar('\n');
putchar(str[2]); putchar('\n'); //tを表示
putchar(a[2]); putchar('\n'); //tを表示
putchar(*b[2]); //. . .(1)
putchar('\n');
return 0;
}
実行結果は以下のようになります。
kitty on your lap
kitty on your lap
kitty on your lap
t
t
Segmentation fault: 11 //. . .(1)
Re: 大学生
Posted: 2015年8月03日(月) 15:07
by amehirune
ポインタのポインタについてはよくわかりませんが、
プログラムを以下のように変更すると期待通りの結果が得られました。
コード:
int main(){
char str[]="kitty on your lap";
char *a;
char **b;
a = str;
b = &a;
printf("%s\n", str);
printf("%s\n", a);
printf("%s\n", *b);
putchar('\n');
putchar(str[2]); putchar('\n'); //tを表示
putchar(a[2]); putchar('\n'); //tを表示
putchar(b[0][2]); //ココ!
putchar('\n');
return 0;
}
*(*b+2) や *(b[0]+2) でもOKなようです。
Re: 大学生
Posted: 2015年8月03日(月) 15:09
by usao
> *b[2]
というのをあなたが
(*b)[2] だと考えているのか,それとも
*( b[2] ) だと考えているのか…
#両者が異なるのはわかりますよね.
Re: ポインタと配列
Posted: 2015年8月03日(月) 15:41
by 大学生
>amehiruneさん
またまたご回答ありがとうございます(^^)
期待した結果を得ることができました!
あと名前とタイトル間違えてました(恥) ご指摘ありがとうございます。
>usaoさん
私は、*(b[2])と考えておりました。でも、*(b)[2]でコンパイルすると期待した結果が得られました(^^)
また*(b)[2]で考えると理解できました!ありがとうございます。
Re: 大学生
Posted: 2015年8月03日(月) 16:44
by Rittai_3D
解決後ですが、説明を書いてみました。
わたしもポインタ関連は苦手なので、間違えている部分もあるかもしれません。
► スポイラーを表示
コード:
#include <stdio.h>
int main( void )
{
char str[] = "kitty on your lap";
char* a;
/* char* 型のポインタ、というイメージ */
char* *b;
/* char* と char[] はシンタックスシュガー */
a = str;
/* こう書いた方が分かりやすい? */
/* b = &a; */
*b = a;
/* 出力 */
printf( "%s\n%s\n%s\n", str, a, *b );
/* char* と char[] は同じ(シンタックスシュガー)
* -> char* 型は一次元配列として表現できる
*/
printf( "%c\n", str[2] );
printf( "%c\n", a[2] );
/* 上と同様に
* char** と char[][] は同じ(シンタックスシュガー)
* -> char** は二次元配列で表現できる
*/
printf( "%c\n", b[0][2] );
/*
* たとえば、変数xがあったとして
* 一次元配列の先頭アドレスは *x のように表される
* 二次元配列の最初の要素の先頭アドレスは ( *x )[ 0 ] と表される
*/
printf( "%c\n", ( *b )[2] );
return 0;
}
[/s]
実行結果です。
# 追記(20:07)
すいません、このコードに間違いが見つかったので修正したものを投稿しました。
大学生 さんが書きました:私は、*(b[2])と考えておりました。でも、*(b)[2]でコンパイルすると期待した結果が得られました(^^)
また*(b)[2]で考えると理解できました!ありがとうございます。
本当に期待した結果が得られたのでしょうか。
実験したところコンパイルは通りましたが何も表示されませんでした。
期待した結果が得られたコードを見せてください。
Re: 大学生
Posted: 2015年8月03日(月) 17:18
by usao
3Dさんのコードの12行目時点で,こんな感じになってると思います.
(矢印で ポインタが指し示す場所 を表しているつもり)

- mem_img.png (7.69 KiB) 閲覧数: 4725 回
ここで 16行目 の
*b = a;
を行うと,
図内 赤枠? の所の値を 'k' を指すように書き換えてしまうと思いますが,
それはまずいのではないでしょうか.
Re: ポインタと配列
Posted: 2015年8月03日(月) 17:48
by 大学生
>3Dさん
すみません、*(b)[2] と (*b)[2] を打ち間違えしておりました(^^;)
コンパイルできたのはuseoさんにご指摘して頂いた (*b)[2] の考え方です。ご迷惑おかけしました。
しかし、3Dさんのコメント付きでの解説すごく分かりやすかったです。今後ポインタをやる上での理解もますます深まりました。ありがとうございました(^^)
>usaoさん
先ほどはありがとうございました。*(b)[2] と (*b)[2] を打ち間違えしておりました(^^;)
丁寧に図まで作って解説してくださりありがとうございます。とても分かりやすいです。ありがとうございました!
Re: 大学生
Posted: 2015年8月03日(月) 20:05
by Rittai_3D
>usaoさん
言われて気がつきましたが、書き変えてしまうのはまずいですね・・・。
先ほどのコードを以下のように修正します。
► スポイラーを表示
コード:
#include <stdio.h>
int main( void )
{
char str[] = "kitty on your lap";
char* a = NULL;
/* char* 型のポインタ、というイメージ */
char* *b = NULL;
/* char* と char[] はシンタックスシュガー */
a = str;
b = &a;
/* 出力 */
printf( "%s\n%s\n%s\n", str, a, *b );
/* char* と char[] は同じ(シンタックスシュガー)
* -> char* 型は一次元配列として表現できる
*/
printf( "%c\n", str[2] );
printf( "%c\n", a[2] );
/* 上と同様に
* char** と char[][] は同じ(シンタックスシュガー)
* -> char** は二次元配列で表現できる
*/
printf( "%c\n", b[0][2] );
/*
* たとえば、変数xがあったとして
* 一次元配列の先頭アドレスは *x のように表される
* 二次元配列の最初の要素の先頭アドレスは ( *x )[ 0 ] と表される
*/
printf( "%c\n", ( *b )[2] );
return 0;
}
実行結果です。
Re: 大学生
Posted: 2015年8月04日(火) 01:24
by きゃりーわんわん
解決済みですがコメントさせてください。
大学生 さんが書きました:
>usaoさん
先ほどはありがとうございました。*(b)[2] と (*b)[2] を打ち間違えしておりました(^^;)
丁寧に図まで作って解説してくださりありがとうございます。とても分かりやすいです。ありがとうございました!
質問者さんも既に理解されていますが、
*b[2]と記載した場合、(*b)[2]ではなく*(b[2])と解釈されます。
# *(b[2]) ⇒ b[2][0]
# (*b)[2] ⇒ b[0][2]
これは演算子の優先順位によるものです。
書籍を確認するか、webで調べてください。
実際にコードを書く際に演算子の優先順位で迷ったら
()を使用するようにしてください。
# 適切な()は読みやすくなりますが、
# ()を多用すると読みにくくなります。
# 不具合が発生するよりはマシなので、
# コメントなりでカバーするようにしてください。
Re: ポインタと配列
Posted: 2015年8月04日(火) 09:16
by 大学生
>きゃりーわんわんさん
ありがとうございます。演算子に優先があるから()を付けずに書くと思った結果と違うことになってしまうのですね。これからはポインタを使って書くときの優先順位に気をつけてプログラムを書こうと思いました。
分かりやすい解説ありがとうございました(^^)