« C言語のお勉強 ポインタ編 第2回 | トップページ

2013年5月23日 (木)

C言語のお勉強 ポインタ編 第3回

先生

ポインタ変数も変数だ

生徒

そうですね

先生

ポインタ変数にもとうぜん識別番号が振られている。識別番号は喩えだが

生徒

そういうことになりますね

先生

ポインタ変数の識別番号を格納する変数もまたポインタ変数だ

生徒

あれ?そこはポインタへのポインタとか言うんじゃないですか?

先生

違うぞ。ポインタ変数はポインタ変数だ

生徒

どういうことですか?

先生

ポインタ変数に格納されるのは識別番号だ

生徒

そうですね

先生

変数は値を入れる箱で、識別番号は箱と一対一に対応するものだ

生徒

そうですね

先生

識別番号は箱を指すものだ。識別番号を指す識別番号というものは存在しない

生徒

煙に巻かれた気分です

int *p;
int **pp;
pp = &p;
先生

変数pの型はintへのポインタと言うのだ

生徒

intを指すのですね

先生

変数ppの型はintへのポインタへのポインタと言うのだ

生徒

intへのポインタを指すのですね

先生

そうだっ!!!そのとおりだっ!!!

生徒

びっくりするから大声出さないでください。何がそのとおりなんですか?

先生

intへのポインタを指すポインタだからintへのポインタへのポインタなのだ。intを指すポインタへのポインタではないぞ

生徒

そういうことですか…あれ?何も指していない変数pを使っていけないのでは?

先生

なんだ君は。分かっているのか分かっていないのかどっちなんだ

生徒

どうして怒られるのか分かりません

先生

ポインタは指すべき箱さえあれば良いのだよ。変数pの箱から識別番号を取得して変数ppに代入することに何ら問題はない

生徒

intはどこに?

先生

intに対応するのは変数pに格納される識別番号だが、変数pの箱の中にはアクセスしていないぞ。よく見たまえ

生徒

確かにそうですね

先生

*ppで変数pの箱にアクセスできる

生徒

そうすると何が起きるか分からないことになるのですね

先生

それも違うぞ

生徒

ええっ?

先生

変数pの箱の中にあるのはあくまでも識別番号だ。正規のものでないというだけだ

生徒

と言うと?

先生

正規の識別番号じゃないと対応する箱が存在しない。だから間接演算子(*演算子)を使って逆参照してはいけない

生徒

そうなんですか

先生

そもそも正規のものでない値を読み出すことは厳禁なのだ。これは識別番号に限ったことではない

生徒

そう…なんですか?

先生

おいおい大丈夫かい?覚束ないのはポインタだけではないようだね

生徒

…すみません

先生

*ppは箱に繋がっているが**ppだと箱に繋がっていないからそこは時空の狭間だ。中身以前の問題というわけさ

生徒

まだよく理解できませんが、箱を意識することが大切なんですね

【2013/05/26 追記】

トラップ表現を考慮し言語仕様に準拠すると思われる表現に変更した。

以下は変更前の内容。

先生

間接演算子(*演算子)を使って逆参照したとき正規の識別番号じゃないと箱は存在しないから問題がある。だが逆参照しない限り問題はない

生徒

そうなんですか

先生

*ppはどんな値か分からなくても箱に繋がっている。**ppだと箱に繋がっていないから異次元への扉が開くというわけだ

|

« C言語のお勉強 ポインタ編 第2回 | トップページ

C/C++」カテゴリの記事

日記・コラム・つぶやき」カテゴリの記事

コメント

> 先生「*ppはどんな値か分からなくても箱に繋がっている。
これは ISO(JIS) C/C++ では正しくないです。初期化されていない自動変数は
その型の有効な値とならない( "trap representation" である)可能性もあり、
そのような値は読み出しのみ(例えば int *q = *pp; )を含めて一切の使用は
未定義動作になります。
ISO C draft N1570 6.2.6.1 p5, ISO C draft N3690 4.1p2

少し前に「生徒」が *pp にアクセスした場合について言っている「そうすると
何が起きるか分からないことになるのですね」が正解だと思います。

投稿: k_satoda | 2013年5月25日 (土) 午後 04時45分

コメントありがとうございます。

6.2.6.1の規定で未定義の動作となるのは、文字型ではない左辺値式でトラップ表現を読み取る場合と文字型ではない左辺値式の副作用でトラップ表現が生成される場合です。
ご指摘のint *q = *pp;は後者に当たります。

これは値の読み出しに限定されます。
int型変数iを使って*pp = &i;とするのは未定義の動作とはなりません。

明らかに問題があるのは先生の「逆参照しない限り問題はない」という部分ですね。
全体にもっとぼかした表現に改めたいと思います。

投稿: ISLe | 2013年5月26日 (日) 午前 01時16分

コメントを書く



(ウェブ上には掲載しません)




« C言語のお勉強 ポインタ編 第2回 | トップページ