Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

  1. トップページ
  2. C言語辞典
  3. ポインタと配列

ポインタと配列

C言語では配列とポインタは密接な関係にあります。配列名は先頭要素へのポインタとして扱われ、ポインタに整数を加算することで次の要素のアドレスに移動できます(ポインタ演算)。

構文
// 配列名はそのまま先頭要素へのポインタとして使えます。
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr; // &arr[0] と同じです。

// インデックス記法とポインタ記法は等価です。
arr[i]      // インデックス記法
*(arr + i)  // ポインタ記法

// ポインタのインクリメントで次の要素に進みます。
p++;     // sizeof(int) バイト分だけアドレスが進みます。
p += n;  // n要素分だけアドレスが進みます。

// ポインタを介して関数に配列を渡します。
void func(int *arr, int size);
void func(int arr[], int size); // 上と同じ意味です。
ポインタと配列の対応
記法同等な表現概要
arr&arr[0]配列先頭要素のアドレスです。
*arrarr[0]配列先頭要素の値です。
arr + i&arr[i]i番目の要素のアドレスです。
*(arr + i)arr[i]i番目の要素の値です。
p++次の要素へ移動型のサイズ分だけアドレスを増やします。
p2 - p1要素数の差2つのポインタが何要素分離れているかを返します。
サンプルコード
#include <stdio.h>

// 配列をポインタとして受け取り、合計を返す関数です。
int sum(int *arr, int size) {
    int total = 0;
    for (int i = 0; i < size; i++) {
        total += arr[i]; // *(arr + i) と同じです。
    }
    return total;
}

// ポインタ演算でループする別の書き方です。
void print_array(const int *p, int size) {
    const int *end = p + size; // 末尾の次のアドレスです。
    while (p < end) {
        printf("%d ", *p);
        p++; // 次の要素に進みます。
    }
    printf("\n");
}

int main(void) {
    int scores[] = {80, 75, 90, 65, 88};
    int n = sizeof(scores) / sizeof(scores[0]);

    // インデックス記法とポインタ記法は等価です。
    printf("scores[2] = %d\n", scores[2]);     // 『90』と出力されます。
    printf("*(scores+2) = %d\n", *(scores+2)); // 『90』と出力されます。

    // ポインタ変数を使って配列を操作します。
    int *p = scores;
    printf("*p = %d\n", *p);    // 先頭: 『80』と出力されます。
    p++;
    printf("*p = %d\n", *p);    // 次の要素: 『75』と出力されます。

    // 関数に配列を渡します。
    printf("合計: %d\n", sum(scores, n)); // 『合計: 398』と出力されます。
    print_array(scores, n);               // 『80 75 90 65 88』と出力されます。

    // 2次元配列とポインタの関係です。
    int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};
    // matrix[i][j] は *(*(matrix + i) + j) と同じです。
    printf("matrix[1][2] = %d\n", *(*(matrix + 1) + 2)); // 『6』と出力されます。

    return 0;
}
概要

配列名はポインタのように使えますが、本質的な違いがあります。配列名はそれ自体がアドレスであり、別のアドレスを代入することはできません。一方、ポインタ変数は任意のアドレスを格納でき、インクリメントや代入が可能です。

関数に配列を渡すと、配列のサイズ情報は失われます。関数内で『sizeof(arr)』を使っても配列全体のサイズではなくポインタのサイズが返ります。配列サイズは必ず別引数として渡してください。

ポインタの基本については『ポインタの基本』を参照してください。文字列(char配列)とポインタの関係は『ポインタと文字列』で解説しています。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。