C言語

【C言語】第4章第5回:ポインタと配列の関係を理解する

ポインタと配列はC言語で非常に密接な関係を持っています。この章では、ポインタを使って配列を操作する方法を、日常的な具体例を交えてわかりやすく解説します。

1. ポインタと配列の基本的な関係

配列とポインタの関係を理解するために、まず基本的な概念を整理しましょう。

1.1 配列は「住所のリスト」

配列は、連続したメモリ領域に値を格納します。それぞれの要素には「アドレス(住所)」が割り当てられています。

  • 配列の先頭アドレスは、配列の名前で表されます。
  • numbersという配列がある場合、numbersは配列の先頭要素のアドレスを指します。

1.2 配列の名前はポインタとして機能する

例えるなら、配列の名前は「リストの案内役」です。配列の各要素を訪ねるには、この案内役を起点に進めば良いのです。

例:配列の名前とポインタ

#include <stdio.h>

int main() {
    int numbers[] = {10, 20, 30};
    printf("Address of numbers: %p\n", (void*)numbers);
    printf("Address of first element: %p\n", (void*)&numbers[0]);

    return 0;
}

1.3 メモリアクセスの仕組み

配列の要素にアクセスする場合:

  • numbers[0]は、先頭アドレスを基準に0番目の要素を指します。
  • *(numbers + 1)は、先頭アドレスに1つ分のメモリを加算した場所を指します。

2. 配列をポインタで操作する

配列をポインタで操作する方法を学びましょう。これは、配列の名前をポインタに割り当てることで実現します。

2.1 ポインタを使った配列アクセス

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

#include <stdio.h>

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int *ptr = numbers; // 配列の先頭アドレスをポインタに格納

    for (int i = 0; i < 5; i++) {
        printf("numbers[%d] = %d (via ptr: %d)\n", i, numbers[i], *(ptr + i));
    }

    return 0;
}

解説:

  • int *ptr = numbers;: 配列の先頭アドレスをポインタに格納します。
  • *(ptr + i): ポインタ演算を使って、配列要素にアクセスします。

3. ポインタと配列の違いを明確に理解する

ポインタと配列は似ていますが、完全に同じではありません。以下の表で違いを整理します:

特徴ポインタ配列
サイズ変更ポインタは動的にサイズ変更可能配列は固定サイズ
名前ポインタは任意の名前を付けられる配列名は固定
メモリアドレスポインタは任意のアドレスを指せる配列名は先頭アドレスに固定

4. 練習問題

以下の課題に挑戦して、ポインタと配列の関係を深く理解しましょう。

  1. ポインタを使って配列のすべての要素を2倍にするプログラムを作成してください。
  2. 配列の逆順をポインタを使って出力するプログラムを作成してください。
  3. ポインタを使って、配列の中で最大値を探すプログラムを作成してください。

5. 練習問題の解答と解説

問1の解答

#include <stdio.h>

int main() {
    int numbers[] = {1, 2, 3, 4, 5};
    int *ptr = numbers;

    for (int i = 0; i < 5; i++) {
        *(ptr + i) *= 2; // 値を2倍にする
    }

    printf("Doubled array: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", numbers[i]);
    }
    printf("\n");

    return 0;
}

6. まとめ

ポインタと配列の関係を理解することで、C言語プログラミングの効率性と柔軟性が向上します。次のステップとして、配列とポインタを活用した高度な操作に挑戦してみましょう。