C言語

【C言語】第3章第8回:配列とポインタの関係性

C言語では、配列とポインタは非常に密接な関係があります。この章では、配列とポインタの仕組みを詳細に解説し、その相互作用を理解するためのプログラム例を示します。

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

配列とポインタは、C言語において非常に似た挙動を示しますが、異なる目的で使用されます。

配列:連続したメモリ領域に格納される同じ型の要素の集合。

ポインタ:メモリアドレスを格納する変数。

配列の名前自体がポインタのように動作し、配列の先頭要素のアドレスを指します。

例:配列名とポインタの挙動

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50}; // 配列を宣言し初期化
    printf("Address of numbers: %p\n", (void*)numbers);        // 配列名は先頭要素のアドレス
    printf("Address of numbers[0]: %p\n", (void*)&numbers[0]); // 同じアドレスを出力
    printf("Value at numbers: %d\n", *numbers);                // 配列の先頭要素の値を取得
    return 0;
}

解説:

  • numbers:配列の先頭アドレスを指すポインタのように動作。
  • &numbers[0]:配列の最初の要素のアドレス。
  • *numbers:ポインタとしての配列名を使い、先頭要素の値を取得。

2. 配列のインデックス操作とポインタ演算

配列の要素は、インデックスを使ってアクセスできます。また、ポインタ演算を使っても同じ操作が可能です。

例:インデックスとポインタ演算の比較

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50}; // 配列を宣言し初期化
    for (int i = 0; i < 5; i++) {
        printf("numbers[%d] = %d, *(numbers + %d) = %d\n", 
               i, numbers[i], i, *(numbers + i)); // インデックスとポインタ演算を比較
    }
    return 0;
}

解説:

  • numbers[i]*(numbers + i)は同じ値を返します。
  • ポインタ演算numbers + iは、配列の先頭アドレスにi * sizeof(int)を加算したアドレスを指します。

3. ポインタによる配列要素の操作

ポインタを使って配列の要素を操作する方法を学びます。

例:ポインタを使った要素の変更

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50}; // 配列を宣言し初期化
    int *ptr = numbers; // 配列の先頭を指すポインタを宣言

    for (int i = 0; i < 5; i++) {
        *(ptr + i) *= 2; // ポインタを使って要素を2倍に変更
    }

    for (int i = 0; i < 5; i++) {
        printf("numbers[%d] = %d\n", i, numbers[i]); // 変更後の値を出力
    }

    return 0;
}

解説:

  • int *ptr = numbers;:配列の先頭要素を指すポインタを宣言。
  • *(ptr + i):ポインタ演算で配列要素を操作。

4. 配列と関数の連携

配列を関数の引数として渡す方法を解説します。配列はポインタとして渡され、配列の内容を操作できます。

例:関数を使った配列の操作

#include <stdio.h>

void doubleArray(int *arr, int size) { // 配列をポインタとして受け取る
    for (int i = 0; i < size; i++) {
        arr[i] *= 2; // 配列の各要素を2倍にする
    }
}

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};

    doubleArray(numbers, 5); // 関数に配列を渡す

    for (int i = 0; i < 5; i++) {
        printf("numbers[%d] = %d\n", i, numbers[i]); // 変更後の値を出力
    }

    return 0;
}

解説:

  • int *arr:配列をポインタとして関数に渡します。
  • 配列全体がコピーされるのではなく、参照が渡されるため、関数内での変更が元の配列に反映されます。

5. 練習問題

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

  1. 配列の要素をポインタを使って1から順に加算するプログラムを作成してください。
  2. 配列を関数に渡し、最大値と最小値を求めるプログラムを作成してください。
  3. ユーザーが入力した値を配列に格納し、ポインタ演算でその平均値を計算してください。

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

問1の解答

#include <stdio.h>

int main() {
    int numbers[5] = {10, 20, 30, 40, 50};
    int *ptr = numbers;

    for (int i = 0; i < 5; i++) {
        *(ptr + i) += i + 1; // 要素に1から順に加算
    }

    for (int i = 0; i < 5; i++) {
        printf("numbers[%d] = %d\n", i, numbers[i]); // 変更後の値を出力
    }

    return 0;
}

7. まとめ

配列とポインタの関係を理解することで、メモリ操作や効率的なデータ管理が可能になります。C言語の強力な特徴を活かし、より複雑なプログラムに挑戦してみましょう。