キーワード辞典
かなり乱暴な変数とポインタの話

登録日 13/04/27   更新日 13/04/27


変数

プログラムを書く際、プログラマは、 分岐先やデータの記憶場所がメモリ上の何番地になるのか、なんて一々考えたくないし、 しかも、プログラムを書き換える度に番地は変わるし、 どうせなら味気ない数字よりも判りやすい名前の方が良い。 そこで、プログラムを書く際には、目印として番地の代わりに名前を付けておき、 コンパイラやアセンブラはその名前の場所が何番地になるのかを計算して 番地に付け替えてくれる様になっている。 つまり、変数名とか関数名とか、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番地)
  ↓
-+--+--+--+--+-
 |           | 
-+--+--+--+--+-

メモリに記憶されているのは0と1の信号の集まりなので、 そのデータを取り出すには、 目印のアドレスを基準にして何語の大きさなのか、 データの型は文字なのか整数なのか実数なのか、などを把握しておかないと、 取り出した値が本来と違ったものになってしまう。 この辺りの定義はプログラム言語の中で行われているが、知っておくと便利な事も多く、 また、個人的には、これを「レディメイドなオブジェクト」と捉えることで、 次の「オブジェクト指向」につながるものだと考えている。


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などと書く。


ポインタの型

ポインタ変数自体は、番地を記憶するための変数なのだから、 色々なデータ型は存在しない筈である。 しかし、何故、番地を記憶する為のポインタ変数にデータ型が有るのかと言えば、 前述の4行目の、
*p=200;
などの様に、ポインタが指し示す番地のデータを操作したい場合、 上の「変数」のところで書いた様にデータ型によって必要な語数が違うため、 ポイントするデータの型が判っていないと、文字のつもりが頓珍漢な数値になったり、実数のつもりが全然違う整数になったり、 データが滅茶苦茶になってしまうからである。

つまり、int *p; は、int型の変数を操作するためのポインタ変数、p という意味になり、 ポインタが示す番地の中のデータを扱う場合は、そのポインタのデータ型の大きさ(文字列の場合は'\0'に辿り着くまでの大きさ)で、 ガバッと出し入れする、ということになる。

また、配列などで、ポインタ変数を、
p++;
等の様に使う場合も、番地をデータ型の大きさ単位で移動し、正しく次のデータの最初の番地を指し示す様になっている。





[ 赤い玉の画像 ] 「キーワード辞典」の目次へ

[ 黒板消しとチョーク受けの画像 ]