C言語

【C言語】第4章第7回:ダブルポインタとその応用

ダブルポインタは、ポインタを指すポインタのことです。この章では、ダブルポインタの基本から応用までを、具体例を交えながら解説します。

1. ダブルポインタとは?

ダブルポインタは、ポインタへのアドレスを格納するポインタです。次のように宣言します:

data_type **pointer_name;

1.1 メモリ階層をイメージする

ダブルポインタを使うと、次のようなメモリ階層を操作できます:

  • 最上位:ダブルポインタ(ポインタのアドレス)
  • 中間:シングルポインタ(変数のアドレス)
  • 最下位:変数そのもの(値)

例:ダブルポインタの基本構造

#include <stdio.h>

int main() {
    int number = 42;
    int *ptr = &number;      // ポインタptrはnumberを指す
    int **dptr = &ptr;       // ダブルポインタdptrはptrを指す

    printf("Value of number: %d\n", number);
    printf("Address of number: %p\n", (void*)&number);
    printf("Value of ptr: %p\n", (void*)ptr);
    printf("Value at *ptr: %d\n", *ptr);
    printf("Value of dptr: %p\n", (void*)dptr);
    printf("Value at *dptr: %p\n", (void*)*dptr);
    printf("Value at **dptr: %d\n", **dptr);

    return 0;
}

解説:

  • int **dptr = &ptr;: ダブルポインタdptrは、ポインタptrを指します。
  • **dptr: ダブルポインタが最終的に指す値(numberの値)。

2. ダブルポインタを使う利点

ダブルポインタを使用することで、以下のような操作が可能になります:

  • 関数内でポインタを操作・変更する。
  • 動的メモリの管理を効率化する。
  • 多次元配列を操作する。

2.1 ポインタを関数で変更する

例:関数内でポインタの参照先を変更

#include <stdio.h>

void updatePointer(int **dptr) {
    static int newNumber = 99;
    *dptr = &newNumber; // ポインタの参照先を変更
}

int main() {
    int number = 42;
    int *ptr = &number;

    printf("Before update: %d\n", *ptr);
    updatePointer(&ptr);
    printf("After update: %d\n", *ptr);

    return 0;
}

解説:

  • int **dptr: ダブルポインタを使用して、関数内でポインタの参照先を変更します。
  • 新しい変数newNumberのアドレスをptrに割り当てることで、呼び出し元での値が変化します。

3. ダブルポインタと動的メモリ管理

ダブルポインタを使うと、動的にメモリを割り当てるポインタを関数内で操作できます。

例:動的メモリの割り当てと解放

#include <stdio.h>
#include <stdlib.h>

void allocateArray(int **arr, int size) {
    *arr = (int *)malloc(size * sizeof(int));

    for (int i = 0; i < size; i++) {
        (*arr)[i] = i + 1;
    }
}

int main() {
    int *array = NULL;
    int size = 5;

    allocateArray(&array, size);

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

    free(array);
    return 0;
}

解説:

  • ダブルポインタint **arrを使用して、関数内で動的メモリを割り当てます。
  • 配列の内容を初期化し、呼び出し元で利用可能にします。

4. 練習問題

以下の課題に挑戦して、ダブルポインタのスキルを磨きましょう。

  1. ダブルポインタを使って2次元配列を動的に割り当て、すべての要素を初期化するプログラムを作成してください。
  2. 関数内でポインタの参照先を変更し、変更内容を呼び出し元に反映するプログラムを作成してください。
  3. ダブルポインタを使って文字列を操作し、すべての文字を大文字に変換するプログラムを作成してください。

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

問1の解答

#include <stdio.h>
#include <stdlib.h>

void allocate2DArray(int ***arr, int rows, int cols) {
    *arr = (int **)malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; i++) {
        (*arr)[i] = (int *)malloc(cols * sizeof(int));
        for (int j = 0; j < cols; j++) {
            (*arr)[i][j] = i * cols + j;
        }
    }
}

int main() {
    int **matrix = NULL;
    int rows = 3, cols = 4;

    allocate2DArray(&matrix, rows, cols);

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);

    return 0;
}

6. まとめ

ダブルポインタは、関数内でのポインタ操作、多次元配列の操作、動的メモリ管理などに広く活用されます。次のステップとして、実際のプログラムに応用してみましょう。