配列とポインタ

配列は、データがメモリ上に順に並んでいるので、ポインタと相性がいい。前のエントリでさらっと書いたけど、配列名を添字を付けずに使うと、先頭を指すポインタを返す。

int a[10];
int *p;

p = a;

配列の要素にポインタでアクセス

配列の各要素には、添字を使ってアクセスするほかにポインタを使ってもアクセスできる。

#include

int main(void)
{
    int a[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
    int *p;

    p = a;

    printf("%d %d %d\n", a[0], a[1], a[2]); /* access with index */
    printf("%d %d %d\n", *p, *(p + 1), *(p + 2)); /* access with pointer */

    return 0;
}
takatoh@nightschool $ ./sample_6_3a
10 20 30
10 20 30

2次元配列

2次元配列の場合は、ポインタを型キャストしてやる必要がある。これはよくわからないな。次のような float 型の2次元配列の要素にアクセスするには、float 型のポインタでいいんじゃなかろうか。

#include

int main(void)
{
    float balance[5][5] = {
        { 1.0, 2.0, 3.0, 4.0, 5.0},
        { 6.0, 7.0, 8.0, 9.0, 10.0},
        {11.0, 12.0, 13.0, 14.0, 15.0},
        {16.0, 17.0, 18.0, 19.0, 20.0},
        {21.0, 22.0, 23.0, 24.0, 25.0}
    };
    float *p;

    p = balance;

    printf("%f\n", *p);
    printf("%f\n", *(p + 1));

    return 0;
}

これを試してみると:

takatoh@nightschool $ gcc sample_6_3b.c -o sample_6_3b
sample_6_3b.c: In function ‘main’:
sample_6_3b.c:15:3: warning: assignment from incompatible pointer type [enabled by default]
 p = balance;
   ^
takatoh@nightschool $ ./sample_6_3b
1.000000
2.000000

出力結果は予想どおりだけど、コンパイル時に warning が出ている。互換性のないポインタを代入している、ということらしい。でもちゃんと動いてるんだけど…。

ポインタへの代入を次のように直すと warning は出なくなった。

#include

int main(void)
{
    float balance[5][5] = {
        { 1.0, 2.0, 3.0, 4.0, 5.0},
        { 6.0, 7.0, 8.0, 9.0, 10.0},
        {11.0, 12.0, 13.0, 14.0, 15.0},
        {16.0, 17.0, 18.0, 19.0, 20.0},
        {21.0, 22.0, 23.0, 24.0, 25.0}
    };
    float *p;

    p = (float *) balance;

    printf("%f\n", *p);
    printf("%f\n", *(p + 1));

    return 0;
}
takatoh@nightschool $ gcc sample_6_3c.c -o sample_6_3c
takatoh@nightschool $ ./sample_6_3c
1.000000
2.000000

ポインタの添字

ポインタが配列を指しているときに限って、ポインタに添字をつけることができる。

#include

int main(void)
{
    char str[] = "Pointer is interesting.";
    char *p;
    int i;

    p = str;

    for (i = 0; p[i]; i++) {
        printf("%c", p[i]);
    }
    printf("\n");

    return 0;
}
takatoh@nightschool $ ./sample_6_3d
Pointer is interesting.

配列のアドレスを使う

最初に書いたように、配列名を添字を付けずに書くとその配列の先頭を指すポインタを返す。なのでこれを普通のポインタの代わりに使うこともできる。

#include

int main(void)
{
    char str[80];

    *(str + 3) = 'c';

    printf("%c\n", *(str + 3));

    return 0;
}
takatoh@nightschool $ ./sample_6_3e
c

[追記]

コメントをもらった。配列名を添字なしで使ったときにポインタのように振る舞うのは、暗黙の型変換が行われるからだそう。配列名の型自体はあくまで配列だと。
ふーむ、なるほど。でも、参照するときに限って言えば、暗黙の型変換のおかげで実質的にポインタとして(というかポインタの代わりに)使えるってことでいいのかな。

「配列とポインタ」への1件のフィードバック

  1. 配列名はあくまで配列を表します。 int a[10]; と定義したとき a の型は int[10] であって、それを int* 型の変数に代入できるのは暗黙の型変換が働いているからです。
    二次元の配列になると実質的には問題なくとも型の辻褄が合わなくなるので警告されることになります。 キャストが不恰好に感じるのであれば p = balance[0]; という風にするか p = &balance[0][0]; とする方法もあります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください