第七回 11 月 17 日

4 ポインタ

ここでは C で最も強力な(そして多くの初学者にとって習得の難しい)ポインタについて学習する。 ポインタを使うことで参照呼び出し call by reference を実現でき, また, 動的データ構造(後日紹介するキュー構造,スタック構造,ツリー構造などのように入力に従って動的に伸び縮みするデータ構造)を実現できる。

ポインタはメモリアドレスを値とする変数である。 変数がその値を保持しているように, ポインタ型の変数は,それが指し示す変数のアドレスを保持する。 この意味で,通常の変数は直接的に値を参照し, ポインタは間接的に値を参照することができる。

他の変数と同様,ポインタ型の変数も使う前に宣言をしなければならない。 たとえば

    int *aPtr, a;

は,変数 aPtr が int *型,すなわち整数型変数へのポインタであることを表し, 「aPtr は int へのポインタである」とか「aPtr は整数型変数を指し示す」 と読む。これに対し,a は今まで使ってきた通常の変数であり, 整数へのポインタではない。この宣言で * は aPtr だけに適用される。 型宣言の中で,変数の前に * をつけるとその変数はポインタになる。 ポインタはどんなデータ型の変数に対しても宣言することができる。
たとえば,

    int *aPtr, i;
    float *fPtr, f;
    double *dPtr, dx;
    char str[]="Hello, world", *strPtr;

    aPtr = &i;
    fPtr = &f;
    dPtr = &dx;
    strPtr = str;

のようなコードがあったとすると,aPtr は int 型変数へのポインタ, fPtr は float 型変数へのポインタ, dPtr は double 型変数へのポインタ, strPtr は 文字配列へのポインタである。

ポインタは他の型の変数と同じく宣言時に,または, 代入文で初期化しておかなければならない。 ポインタ型の変数への初期値として与えることができるのは, アドレスか 0 または NULL である。NULL は <stdio.h> で定義されている記号定数である。

たとえば次のようなコードがあったとする。

#include <stdio.h>
#include <limits.h>

int main(void)
{
    int a, *aPtr;

    aPtr = &a;
    *aPtr = INT_MAX;

    printf("a=%d\n", a);
    printf("&a=%p\n", &a);
    printf("aPtr=%p\n", aPtr);
    printf("&aPtr=%p\n", &aPtr);

    return 0;
}

このときのメモリイメージは次のようになる。
aPtr.png
ここで,

    printf("%d", *aPtr);    

は変数 a の値すなわち INT_MAX を出力する。 このように * 演算子はポインタの指し示している変数の値を参照するために用いる。

なお上のソースコードで,

    aPtr = &a;
    *aPtr = INT_MAX;

となっているところを,

    a = INT_MAX;
    aPtr = &a;

としても同じ結果が得られる。

4.1 アドレス

変数のアドレスは,変数の前に & をつけて表す。 scanf() 関数,printf() 関数などで関数にアドレスを渡す場合には アドレス変換指定子 %p を使う。アドレスは 16 進数で表示される。 例えば,int 型の変数 a のアドレスを得るには以下のようなプログラムを用いる。 address.c

演習4.1

address.c を変形し char 型の変数 c1, c2, int 型の変数 i1, i2, long long int 型の変数 lli1, lli2, float 型の変数 f1, f2, double 型の変数 d1, d2, long double 型の変数 ld1, ld2, を宣言しアドレスを調べてみよ。宣言する順序を変えるとどうなるか。

演習4.2

演習4.1 より、 char型、int型、long long int型、float型、double型、long double型、 の変数はメモリ上で何バイト占めていると考えられるか。

4.2 ポインタ

すでに記したように,ポインタ型の変数は, 変数や関数などのアドレスを格納する変数である。 たとえば,ポインタ ptr が変数 x のアドレスを 持っている場合,ptr は x を指しているなどと表現する。

例4.2 ポインタとポインタの指す変数

pointer.c
pointer-pointer.c

間接演算子

ポインタに変数のアドレスが格納されると, ポインタ型変数からそのポインタが指している先の変数の値を参照することができる。 このポインタを指す変数の値を与える演算子 * を 間接演算子 indirect operator といったりする。

例4.3 ポインタ型変数 ap から参照先の値を求める。

indirection.c
pointer-wrong.c

例4.4 ポインタを用いて変数の値を変更することができる

pointer2.c
pointer-test1.c
pointer-test2.c
pointer-test3.c
pointer-test4.c
pointer-test5.c
pointer-test6.c


戻る

Shin-ichi ASAKAWA
asakawa@ieee.org