プログラムを書く際、プログラマは、 分岐先やデータの記憶場所がメモリ上の何番地になるのか、なんて一々考えたくないし、 しかも、プログラムを書き換える度に番地は変わるし、 どうせなら味気ない数字よりも判りやすい名前の方が良い。 そこで、プログラムを書く際には、目印として番地の代わりに名前を付けておき、 コンパイラやアセンブラはその名前の場所が何番地になるのかを計算して 番地に付け替えてくれる様になっている。 つまり、変数名とか関数名とか、COBOLなら項目名とか手続き名とか、アセンブラならラベルとかいうものは、 最終的にはそのプログラム上の番地を指しているに過ぎない。
例えば、Cのプログラムで
char a=10;
と書いた場合は、
実行した時に何番地になるか判らないけれど
とりあえず「a」という目印を付けた番地に10という数値を記憶するという意味になる。
じゃあ、実行した時のaの場所(番地)って何処よ、という時は、&aと書く。
例えば、aの番地が3000番地だった場合、a=10、&a=3000になる。
目印a(&a番地=3000番地) ↓ -+--+- |10| -+--+-
データには、文字、整数(単精度、倍精度)、浮動小数点、など、色々なデータ型が有り、
データ型によって記憶する為に必要な連続した領域が1語(1つの番地の大きさ)だったり、
2語だったり、4語だったり、する。
前述の&aでは、各データの一番最初の番地を指す。
例えば、「a」という名前を付けた変数が3000番地~3003番地の4語を使用している場合、
&aの値は3000になる。
目印a(&a番地=3000番地) ↓ -+--+--+--+--+- | | -+--+--+--+--+-
1台のコンピュータ上には複数のプログラム(モジュール、関数、などと置き換えても良い)が実行されている。 各々のプログラムに実行前から予め固定のアドレスが付けられていると プログラム同士でアドレスが重なったり、再帰的に使えなかったりと、何かと不便なので、 予め各々のプログラムには先頭からの相対的なアドレスを付けておき、 実行する際に最終的にアドレスを付け直して主記憶装置に配置する (詳しくは「COMET/CASL」の項を参照)。 この為、各プログラム内で定義されたデータについては、 他のプログラムからはお互いのデータが有る番地を予め知る事が出来ない。 そこで、複数のプログラム間で動的にデータをやり取りする場合には、 値自体を渡す方法と、値が記憶されている番地を渡す方法が有る。 (詳しくは「値渡しと参照渡し」の項を参照)
記憶した値を、データ自体ではなくデータが記憶された「番地」として操作するための変数を、
ポインタ変数と言う。
最初は、Windowsのショートカットを想像してもらえれば良い(わりと特殊だが)。
何故そんなのが要るの、という話は、下の「ポインタの型」と、「配列」を参照。
C言語では、
int a; int型の変数aを宣言。などと書く。
int *p; int型の変数の番地を記憶するためのポインタ変数pを宣言。
宣言する際の*がポインタ変数の目印。
p=&a; 変数aの番地をあらわす&aをポインタ変数pに記憶する。
windowsで言えば、aのショートカットを作った状態。
ここで、*p=&a; と書くと、
ポインタ変数pが記憶している番地に変数aの番地を記憶する意味になるので要注意。
*p=200; ポインタ変数pが記憶している番地(変数aの番地=&a)に200を記憶する。
変数aに200が記憶されることになる。a=200; と同じ。
windowsで言えば、aのショートカットをクリックしaの内容を書き変えた状態。
2行目は、「int *」な変数「p」と考えると判り易いのかも。
ポインタのポインタ、というのもある。 **pなどと書く。
また、配列などで、ポインタ変数を、
p++;
等の様に使う場合も、番地をデータ型の大きさ単位で移動し、正しく次のデータの最初の番地を指し示す様になっている。