配列のようにメモリ上に順番に並んでいるデータに対してポインタを使うと, 効率よくアクセスできる.また,処理を簡潔に表現できることが多いが,反面, 慣れていないとそれを読みこなせない.
C言語では,表現の上で配列とポインタを区別しない部分があるが, 実体は異なるので注意が必要である.
int *p, *q; (中略) q = p + 3; pのアドレスに4*3を足したアドレスをqに代入する. p += 5; pのアドレスを4*5増加させる. q++; qのアドレスを4増加させる.
int *a, *b; (中略) a == b ポインタaとbの値が等しいか? (同じ場所を指しているか) a < b ポインタaがbより小さいアドレスか? (aがbより前方か?) a > b ポインタaがbより大きいアドレスか? (aがbより後方か?)
大小比較は,配列のように連続して確保された領域内を指す 2つのポインタの間でしか意味を持たない.
配列の名前は,その内容が記憶されている場所の先頭 (つまり要素0)のアドレスそのものを表す. 配列名をaとすれば,aと&a[0]は等価である.
配列の要素は,記憶領域(メモリ)上で連続しており, 要素番号の順に並んでいる. したがって,配列の要素番号が大きいほど,ポインタ値(アドレス)が大きい. この性質を利用して, 配列に格納されたデータに対してポインタでアクセスすることがしばしば行なわれる. 実例を示しながら説明していこう.
型の大きさとポインタ+1の大きさを調べる.
配列のように同じ型の変数が順に並んでいる領域へのアクセス (値の参照や代入)に関しては,配列とポインタの区別はない.
配列aの要素iのアドレスと中身は以下のように書くことができる.
&a[i] ←(等価)→ a+i a[i] ←(等価)→ *(a+i)
一方,ポインタ変数pに対しては, そのポインタからオフセットiのアドレスとそれが指す内容を 以下のように書くことができる.
&p[i] ←(等価)→ p+i p[i] ←(等価)→ *(p+i)つまり,アクセスの記述の上では配列もポインタも同じ. 配列変数をポインタ風に*(a+3)と書いても構わないし, ポインタ変数を配列風にp[3]と書いても構わない.
実は,a[3]よりも*(a+3)の方が,コンピュータが実際にやっていることに近い. つまり,配列aの要素3の値にアクセスするには,
上述のアクセス方法のバリエーションの具体例.
では,配列変数とポインタ変数の違いは何なのか?
変数の宣言によって用意される内容が異なる.
int a[7];
int *p;