【C言語】ポインタのポインタについてわかりやすく解説

ポインタのポインタについての基本知識を学ぶことで、C言語におけるポインタの応用的な使い方を理解することができます。

ポインタのポインタを使うことで、関数内でポインタの値を変更したり、複雑なデータ構造を扱ったりすることができます。

この記事では、ポインタのポインタの基本的な使い方や具体的な用途について解説します。

目次から探す

ポインタのポインタについての基本知識

ポインタのポインタ(Pointer to Pointer)は、C言語においてポインタを指すポインタのことを指します。

つまり、ポインタの値が別のポインタを指すような構造を持つことを意味します。

ポインタのポインタとは何か?

ポインタのポインタは、ポインタ変数のアドレスを格納するための変数です。

通常のポインタ変数がメモリ上のアドレスを指し示すのに対して、ポインタのポインタはポインタ変数自体のアドレスを指し示します。

ポインタのポインタは、2重間接参照(Double Indirection)とも呼ばれます。

これは、ポインタを通じて別のポインタを参照することで、より複雑なデータ構造を表現することができます。

ポインタのポインタの利点と用途

ポインタのポインタを使う理由

ポインタのポインタを使用する主な理由は、関数内でポインタの値を変更する必要がある場合です。

通常、関数に渡されたポインタは、関数内での変更が関数外に反映されません。

しかし、ポインタのポインタを使用することで、関数内でポインタの値を変更することができます。

ポインタのポインタの具体的な用途

ポインタのポインタは、多次元配列や動的メモリの管理など、複雑なデータ構造を扱う際に使用されます。

例えば、2次元配列を扱う場合、ポインタのポインタを使用することで、各要素へのアクセスを効率的に行うことができます。

また、動的メモリの管理では、ポインタのポインタを使用して、メモリの確保や解放を行うことができます。

以下に、ポインタのポインタを使用した2次元配列の例を示します。


#include <stdio.h>
int main() {
    int rows = 3;
    int cols = 4;
    // 2次元配列の動的メモリ確保
    int** matrix = (int**)malloc(rows * sizeof(int*));
    for (int i = 0; i < rows; i++) {
        matrix[i] = (int*)malloc(cols * sizeof(int));
    }
    // 2次元配列の初期化
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;
        }
    }
    // 2次元配列の表示
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }
    // 2次元配列の動的メモリ解放
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);
    return 0;
}

上記の例では、int**型のポインタのポインタを使用して、3行4列の2次元配列を動的に確保し、初期化しています。

そして、各要素へのアクセスやメモリの解放を行っています。

ポインタのポインタを使用することで、より柔軟なデータ構造を扱うことができますが、ポインタのポインタの使用は注意が必要です。

メモリの解放を忘れたり、ポインタの参照先が無効なアドレスを指している場合には、予期しないエラーが発生する可能性があります。

適切なメモリ管理とエラーチェックを行うことが重要です。

ポインタのポインタの実装方法

ポインタのポインタは、ポインタを指すポインタのことを指します。

つまり、ポインタのアドレスを格納するための変数です。

ポインタのポインタの初期化方法

ポインタのポインタを初期化するには、まずポインタのポインタ変数を宣言します。

その後、ポインタのポインタ変数に対して、ポインタのアドレスを代入します。

以下に、ポインタのポインタの初期化方法の例を示します。


#include <stdio.h>
int main() {
    int num = 10;
    int *ptr = &num; // ポインタ変数ptrにnumのアドレスを代入
    int **pptr = &ptr; // ポインタのポインタ変数pptrにptrのアドレスを代入
    printf("numの値: %d\n", num);
    printf("ptrの値: %p\n", ptr);
    printf("pptrの値: %p\n", pptr);
    return 0;
}

上記の例では、まずint型の変数numを宣言し、そのアドレスをint型のポインタ変数ptrに代入しています。

そして、int型のポインタのポインタ変数pptrには、ptrのアドレスを代入しています。

ポインタのポインタの操作方法

ポインタのポインタを操作するには、2重の間接参照演算子(**)を使用します。

これにより、ポインタのポインタが指す値にアクセスすることができます。

以下に、ポインタのポインタの操作方法の例を示します。


#include <stdio.h>
int main() {
    int num = 10;
    int *ptr = &num; // ポインタ変数ptrにnumのアドレスを代入
    int **pptr = &ptr; // ポインタのポインタ変数pptrにptrのアドレスを代入
    printf("numの値: %d\n", num);
    printf("ptrの値: %p\n", ptr);
    printf("pptrの値: %p\n", pptr);
    printf("pptrが指す値: %p\n", *pptr);
    printf("pptrが指す値の値: %d\n", **pptr);
    return 0;
}

上記の例では、ポインタのポインタ変数pptrが指す値(ptrのアドレス)を表示するために、*pptrを使用しています。

また、pptrが指す値(ptrのアドレス)が指す値(numの値)を表示するために、**pptrを使用しています。

ポインタのポインタを使った値の取得方法

ポインタのポインタを使って値を取得するには、ポインタのポインタが指す値(ポインタのアドレス)を通じて、元の値にアクセスします。

以下に、ポインタのポインタを使った値の取得方法の例を示します。


#include <stdio.h>
void getValue(int **pptr) {
    printf("pptrが指す値の値: %d\n", **pptr);
}
int main() {
    int num = 10;
    int *ptr = &num; // ポインタ変数ptrにnumのアドレスを代入
    int **pptr = &ptr; // ポインタのポインタ変数pptrにptrのアドレスを代入
    getValue(pptr);
    return 0;
}

上記の例では、getValue関数にポインタのポインタ変数pptrを渡しています。

そして、getValue関数内でpptrが指す値(ptrのアドレス)が指す値(numの値)を表示しています。

ポインタのポインタを使った値の変更方法

ポインタのポインタを使って値を変更するには、ポインタのポインタが指す値(ポインタのアドレス)を通じて、元の値を変更します。

以下に、ポインタのポインタを使った値の変更方法の例を示します。


#include <stdio.h>
void changeValue(int **pptr) {
    **pptr = 20;
}
int main() {
    int num = 10;
    int *ptr = &num; // ポインタ変数ptrにnumのアドレスを代入
    int **pptr = &ptr; // ポインタのポインタ変数pptrにptrのアドレスを代入
    printf("変更前のnumの値: %d\n", num);
    changeValue(pptr);
    printf("変更後のnumの値: %d\n", num);
    return 0;
}

上記の例では、changeValue関数にポインタのポインタ変数pptrを渡しています。

そして、changeValue関数内でpptrが指す値(ptrのアドレス)が指す値(numの値)を変更しています。

その結果、main関数内でnumの値を表示すると、変更後の値が表示されます。

目次から探す