第九回 12 月 15 日

4 ポインタ

4.6 配列とポインタ

a[] という配列変数があったとする。このとき, *(a+1) は a[1] と正確に同じ意味になる。 従って, 配列の n+1 番目の要素を参照したければ *(a+n) となる (このとき,n は int 型の変数でなければならない)。 array_pointer.c

整数型の配列 a[3] と整数型へのポインタ aPtr が宣言されているとする。 添字なしの配列名はその配列の先頭要素へのポインタである。
なので,以下の文のように配列 a の先頭アドレスを aPtr にセットすることができる。

    aPtr = a;

これは配列の先頭要素のアドレスを使った以下の文と同義である。

    aPtr = &a[0];

このとき,配列要素 a[2] は次のポインタの式でも参照可能である。

    *(aPtr + 2)

この式中の 2 は,ポインタ aPtr からどのくらい離れているかを表す数字なり オフセットと呼ばれたりする。 オフセットの数字と配列の添字とは等しい。 * 演算子の方が + 演算子よりも優先順位が高いので「aPtr+3」を括弧で囲む必要がある。 括弧がないと

    *aPtr + 2

は,*aPtr に 2 を足すという意味に解釈されてしまう。 すなわち aPtr は配列の先頭を指しているので a[0] に 2 を加えた数が返される。 ポインタを使って配列の要素にアクセスできるように,

    &a[2]

も以下のようにポインタを使って,

    aPtr + 2

のように表現できる。

配列名自体もポインタとして扱えるので,ポインタ演算を使うことができる。 たとえば,次の式

    *(aPtr + 1)

は,先に述べたように a[1] と同義である。サンプルコードを以下に示す。
pointer_array.c

逆に,ポインタを配列として記述することも可能である。例えば

    aPtr[1]

は,配列要素 a[1] を参照する。 このような書き方をポインタの添字表記法と呼ぶ。 配列表記とポインタ表記を使った文字列のコピーのサンプルコードを以下に示す。 pointer_copy.c

演習 4.6

array_pointer.c の printf() 文の a[0], a[1], a[2] を p[0], p[1], p[2] にして実行せよ。

配列とポインタの関係
ポインタ p 配列 a
配列の先頭要素のアドレスp または &p[0]a または &a[0]
配列の先頭要素*p または p[0]*a または a[0]

次の例は,a[3] という要素の数が 3 である配列 a[3] に対して,intPtr というポインタ変数 に a (すなわち a の先頭の要素のアドレス &a[0])を代入し,その値を調べて,それぞれのアドレスと値を印刷している。 array_pionter2.c

また,次のサンプルプログラムも配列 a[3] の中の 1 番目の要素 a[0] のアドレスと要素の値を印刷している。 array-pionter3.c

演習 4.7 array_pointer3.c を改造し,a[1] のアドレスと値とを出力するようにせよ。

解答例

4.7 引数を配列に持つ関数 その 2

int a[] を引数に持つ関数(例えば max-array-func.c)は, 仮引数に int a[], または int *a として, 実引数は配列名 a とする。call by reference の説明で述べたように, 仮引数の int *a は配列 a を指すポインタであり, 実引数の a は配列 a のアドレスである。
arrayPtr.png

次のサンプルプログラムは, array[i] に代入した値を *(arrayPtr+i) で表示している。 array_pointer4.c

次のサンプルコードはやや複雑にしてある。*arrayPtr は array[10] という配列へのポインタ変数である。従って、*arrayPtr++; は array[10] を参照し,インクリメント ++ することにより,各要素を順に表示している。またその時のアドレスを arrayPtr+i で表示している。 array_pointer5.c

次の例は arraysum() という関数に渡す引数として main 関数では a[N] と配列で宣言してある a を,arraysum() 関数の定義実体ではポンンタとして受け取っている。 array-sum.c

演習 4.9

selection-sort.cをポインタを用いて書き換えよ。 解答例

演習 4.10

演習 3.15の関数をポインタを用いて書き換えよ。
解答例

4.8 文字列の配列とポインタ

次のサンプルコードは char str[4][30]={"こんにちは", "世界", "私の名前は", "浅川だ"}; という文字列の配列を扱ったものである。この例は,
str[0]="こんにちは",
str[1]="世界",
str[2]="私の名前は",
str[3]="浅川だ",
という 4 つの文字列を要素とする配列である。char *strPtr とすれば, str の i 番目の要素を strPtr に代入し, strPtr = *(str+i) とすることで
printf("%s", str[i]); と
printf("%s", strPtr); とは同じ動作をする。 strPtr20081201-01.c

上の例の printf() 文を putchar() 文で置き換えて,ポインターの操作と文字列の配列の操作を示した例が以下のサンプルコードである。
strPtr20081201-02.c
strPtr20081201-03.c
strPtr20081201-04.c
strPtr20081201-05.c
strPtr20081201-06.c

ポンターへのポインターということでしばしば混乱が起こる。 注意してソースコードを読む必要がある。 次のサンプルコードは 2 次元配列 mat[3][3] に対するポンターとして, int *intPtr, **intPtrPtr; を定義している。 double_pointer1.c

文字列へのポンターへのポインターを定義して,ポインタの演算をしているサンプルコードを以下に示す。 double_pointer2.c
double_pointer3.c


戻る

Shin-ichi ASAKAWA
asakawa@ieee.org