変数に値を代入したとき、それがコンピュータのメモリ上にどのように
格納されているかを復習しよう。以下の例では変数の格納されるアドレスが
切り良く 0x1000 番地(16進数)や0x2000番地になっ
ているが、実際は必ずしもそうならない。
整数の場合
int a = 5;
と宣言した場合、メモリ上には次のように変数用の保存場所が確保され、 値である5が入れられる。
↓a | |
||||
0x1000 | 0x1001 |
0x1002 | 0x1003 |
0x1004 |
……… |
5 | ????? |
????? |
|||
この場合、変数aのアドレスを知りたい場合は、
頭に&をつけて、&a とすればよい。
続いて、文字列を考えよう。
char s[] = "hoge";
と宣言した場合のメモリ上の様子は以下のようになる。
↓s |
|||||||
0x2000 | 0x2001 |
0x2002 | 0x2003 |
0x2004 | 0x2006 |
……… |
|
| ASCIIコード | 0x68 | 0x6f |
0x67 | 0x65 |
0x00 |
????? | ????? |
| 文字 | 'h' | 'o' |
'g' | 'e' |
'\0' |
????? | ????? |
変数sは配列となる。配列の各要素と、アドレスの関係は
以下のようになる。
| 各要素 | s[0] | s[1] |
s[2] | s[3] |
s[4] |
|---|---|---|---|---|---|
| そのアドレス | 0x2000 | 0x2001 |
0x2002 | 0x2003 |
0x2004 |
| アドレス表記 | &s[0] | &s[1] |
&s[2] | &s[3] |
&s[4] |
C言語では、何かの値が入っているアドレスを指し示す変数を持つことができる。 どこかに保存されている値を取り出すために持っているアドレス値のことを ポインタという。ポインタとして機能する変数のことを ポインタ変数という。具体例を見よう。
int型の配列
int x[5] = {10, 20, 14, 99, 30};
を宣言する。この状態でポインタ変数 p を宣言し、それが配列 x[]
の先頭を指し示すようにするには以下のように記述する。
int *p; p = x;
ポインタ変数は、変数の頭に * をつける。上記の2行をまとめて
int *p = x;
と書くこともできる。x は配列x[] の先頭のア
ドレスを示すことに注意すると、ポインタ変数pはxの
アドレスを持つ。
↓p (= x = 0x1000) |
||||
0x1000 | 0x1001 |
0x1002 | 0x1003 |
0x1004 |
x[0] | x[1] |
x[2] | x[3] |
x[4] |
10 | 20 |
14 | 99 |
30 |
このとき、*p と書くと、そのアドレスに入っている
int型の値を取り出すことができる。つまり、
p
と書くと、番地を意味するが、
*p
と書くと、そこに入っているもの、つまり10を取り出せる。
さらに、配列x[] の次の値を取り出したいときは
pに1を加えたアドレスを * で参照すると良い。
つまり、
*(p+1)
または
p++;
*p
または
*(++p)
などとするとx[1]の要素である20を取り出すことができる。
int *p と宣言したので、p は「intの値を参照するため」
に増減値が決定する。p+1 とした場合も、実際には
アドレス1番地分が足されるのではなく、intの値のアドレス幅(=4)だけ
加算される。プログラムのときにはpを数値的にいくつ増やすべきかは
気にしなくて良い。