アドレスを操作するとなると,アドレスを入れる変数が欲しくなる. 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;と宣言したとする.