T型の配列
「ポインタ虎の巻」を読んでいたら、今更ながら、こんな盲点に気づかされた。
/* !!! 間違ったコード例 */ int data[3][5]; int **p; p = data; /* Syntax Error !!! */
二次元配列の値を、ポインタのポインタ変数に代入しているので、なんとな〜く正しそうな気はするのだけど、メモリの絵を描いてじっくり考えてみれば、これではコンパイルエラーが出て当然だということに気づく。言われればそうだなーと分かるのだが、C言語に少し慣れてくると、つい気を許してフィーリングに頼ってしまい、初歩的なうっかりミスを犯すことになるから気をつけたいな。
まず、基本から。
式中における配列のシンボル名は、「配列の先頭要素へのポインタ値」に展開される。例えば、「int data[5]」と宣言した場合、式中の配列シンボル「data」は、以下マークがついた要素へのポインタに展開される。
data +-------+-------+-------+-------+-------+ | <int> | <int> | <int> | <int> | <int> | +-------+-------+-------+-------+-------+ 0 4 8 12 16 20 offset *******
そして、二次元配列の場合はどうかというと…
ここではあえて、多次元配列という概念は脇において、「T型の配列」として捉えてみる。
例えば、「int data2[3][5]」という宣言は、「「int型オブジェクトx5で構成された配列」を3要素持つ配列」であるが、これは「T=
data2 +------------+------------+------------+ | <int>[5] | <int>[5] | <int>[5] | +------------+------------+------------+ 0 20 40 ************
したがって、式中での配列のシンボル「data2」は、上でマークしたオブジェクトへのポインタに展開される。先頭の
冒頭に戻ると、以下のコード片における「data」は、
/* (^ ^)正しいコード例 */ int data[3][5]; /* 'data' is an array of <array of int> */ int (*p)[5]; /* 'p' is pointer to an <array of int> */ p = data; /* OK */
今まで、「配列の先頭要素へのポインタ」という表現を使ってきたけど、多次元配列のことを視野に入れて言い直すと、
式中における配列シンボルは、最上位次元の配列の先頭要素へのポインタ値に展開される。 ^^^^^^^^^^^^
多次元配列は「T型の配列」として捉えると綺麗に整理されるよ、というお話でした。