■配列とポインタ

Last modified: Mon April 03 2018
このページは,基礎工学部システム科学科機械科学コース2年生向けの 「コンピュータ基礎演習」における演習1の教材の1つです.

配列のようにメモリ上に順番に並んでいるデータに対してポインタを使うと, 効率よくアクセスできる.また,処理を簡潔に表現できることが多いが,反面, 慣れていないとそれを読みこなせない.

C言語では,表現の上で配列とポインタを区別しない部分があるが, 実体は異なるので注意が必要である.

●ポインタに対する演算

ポインタと整数値の加減算
ポインタ値(アドレス)を,そのポインタの指す対象のサイズを単位として, 加算したり,減算したりする.例えば,int型が4byteの場合,
   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-3 example13.c

型の大きさとポインタ+1の大きさを調べる.

sizeof
記憶量演算子.関数のような形をしているが演算子の一種である.
変数,定数,型名などを引数に取り, そららが記憶領域で占める大きさをバイト数として返す.

●要素へのアクセス方法

配列のように同じ型の変数が順に並んでいる領域へのアクセス (値の参照や代入)に関しては,配列とポインタの区別はない.

配列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の値にアクセスするには,

という一連の作業が行われる(一連の作業を行う機械語の並びに変換される). これは,ソースコードにa[3]と書いても,同じである.

例1-4 example14.c

上述のアクセス方法のバリエーションの具体例.

●違いは何か?

では,配列変数とポインタ変数の違いは何なのか?

変数の宣言によって用意される内容が異なる.

    int a[7]; 
    int *p;


[演習1のインデックス] [前の教材(関数とポインタその1)] [次の教材(関数とポインタその2)]
hirai@me.es.osaka-u.ac.jp