アドレスを操作するとなると,アドレスを入れる変数が欲しくなる. 2.1.1節で述べたように,アドレスは32ビットである.また, int型のデータも32ビットである.従って,int型の変数にアドレスを入れるこ とがあできそうである.具体的には,hogeと言う変数のアドレスをint型の変 数 i に,次のような文で,
i=&hoge;と代入する.しかし,これはコンパイラーにより警告が出され,推奨される方法でない 5.たまたま, 私が使っているコンパイラーでは警告で済んでいるが,エラーを出すものもあるであろう. そもそも,アドレスのビット数とint型のビット数が同じであるのは偶然にすぎない.
幸いなことに,C言語にはアドレスを格納する仕組みが用意されている.ポインターとい う変数を使い,アドレスが格納できるのである.そのアドレスを格納するポインター型変 数は,
int *pi; double *px;と宣言する.アスタリスク(*)をつければ,ポインターの宣言になる.
整数型変数 i と実数型変数 x のアドレスは,&iと &xのようにすると取り出すことができる.アドレス演算子(&)を使うのであ る.取り出したアドレスは,ポインターに
pi=&i; px=&x;のようにして代入できる.アドレス演算子(&)により変数の先頭アドレスを取り出 して,代入演算子(=)を用いて,ポインター型変数に代入している.
ポインター機能は,アドレスの格納のみに止まらず,そのアドレスが示しているデータの 内容も表すことができる.今までの例の通り,ポインターには変数の先頭アドレスが格納 されている.そして,ポインターの宣言の型から,そのポインターが指しているデータの 内容までたぐり寄せることができる.ポインターpiとpxが示しているデータの 値を,整数型変数 j と実数型変数 y に代入する場合
j=*pi; y=*px;とかく.ここで,アスタリスク(*)は間接参照演算子で,ポインターが示しているア ドレスのデータを取り出せるのである.このようにアドレスのみならず,そのアドレスの データの型までポインターは持っているから,これが可能なのである.このことから,アドレ スとは言わずにポインター(pointer 指し示すもの)と言うのであろう.
このプログラムの各行の内容は,以下の通りである.1行毎にきっちり理解することが重 要である.
1 #include <stdio.h> 2 3 int main(void){ 4 int *p; 5 int i=0x11223344; 6 7 p=&i; 8 9 printf("address i %p\n", &i); 10 printf("address p %p\n", &p); 11 12 printf("value i %0x\n", i); 13 printf("value p %0x\n", (unsigned int)p); 14 15 printf("value *p %0x\n", *p); 16 17 return 0; 18 }
address i 0xbffff6b0 address p 0xbffff6b4 value i 11223344 value p bffff6b0 value *p 11223344
この実行結果から,メモリーは図6のようになっていること が分かる.ポインター p には,整数変数 i の先頭アドレスが格納されている. さらに,ポインターpに間接参照演算子*を作用(*p)させることにより, ポインターが指し示すアドレスの内容を取り出している.また,どんな変数でも, アドレス演算子&で,メモリーのアドレスが取り出せている.これらのことをしっかり理解 すると,ポインターは難しくない.
char c, *cp; int i, *ip; double x, *xp;と宣言したとする.