Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

C言語入門:ダブルポインタ(ポインタへのポインタ)とvoidポインタの基本をわかりやすく解説

C言語には、通常のポインタ以外にも「ポインタへのポインタ(ダブルポインタ)」「voidポインタ」といった便利な概念があります。この記事では、それぞれの宣言方法・初期化・値へのアクセス方法を、実際に動作するサンプルコードとともにわかりやすく解説します。

ダブルポインタ(ポインタへのポインタ)とは

ダブルポインタとは、別のポインタ変数のアドレスを格納する変数のことです。通常のポインタが「変数のアドレス」を保持するのに対し、ダブルポインタは「ポインタのアドレス」を保持するという点が特徴です。

宣言方法

ポインタへのポインタは、アスタリスク(*)を2つ重ねて次のように宣言します。

datatype **pointer_name;

例えば、int **p; と宣言した場合、p は「int型変数へのポインタ」を指すポインタとなります。

初期化

初期化には、アドレス演算子「&」を使用します。

int a = 10;
int *p;
int **q;
p = &a;   /* p に変数 a のアドレスを代入 */
q = &p;   /* q にポインタ p のアドレスを代入 */

値へのアクセス

格納されている値にアクセスするには、間接演算子「*」を使用します。ダブルポインタの場合は「**」を2回適用することで、最終的な変数の値を取得できます。

  • *p … ポインタ p が指す変数 a の値
  • **q … ダブルポインタ q が指す先(ポインタ p)が指す変数 a の値

サンプルプログラム

#include <stdio.h>

int main(void) {
    int A = 10;
    int *p;
    int **q;

    p = &A;
    q = &p;

    printf("A = %d\n", A);
    printf("ポインタ経由のAの値 = %d\n", *p);
    printf("ダブルポインタ経由のAの値 = %d\n", **q);

    return 0;
}

実行結果

A = 10
ポインタ経由のAの値 = 10
ダブルポインタ経由のAの値 = 10

このように、直接アクセス・ポインタ経由・ダブルポインタ経由のいずれの方法でも、同じ値「10」を取得できることが確認できます。

voidポインタとは

voidポインタは、あらゆるデータ型の変数のアドレスを格納できる汎用ポインタです。int型でも float型でも、どのような型の変数であっても指し示すことができるため、「型を持たないポインタ」と呼ばれることもあります。

宣言方法

void *pointername;

例えば、void *vp; のように宣言します。

値へのアクセス(型キャスト)

voidポインタが指す値にアクセスする際は、型キャスト演算子を使って元の型に戻す必要があります。voidポインタは型情報を持たないため、直接参照(*vp)することはできません。

構文は以下の通りです。

*( (type_cast) void_pointer )

例:

int i = 10;
void *vp;

vp = &i;
printf("%d", *( (int *) vp ));   /* int型ポインタにキャストして参照 */

サンプルプログラム

1つのvoidポインタを使って、int型とfloat型の両方の変数を扱う例を紹介します。

#include <stdio.h>

int main(void) {
    int i = 10;
    float f = 5.34;
    void *vp;

    vp = &i;
    printf("i = %d\n", *( (int *) vp));

    vp = &f;
    printf("f = %f\n", *( (float *) vp));

    return 0;
}

実行結果

i = 10
f = 5.34

このように、同じvoidポインタ vp でも、キャストする型を切り替えることで、int型・float型など異なる型の変数を柔軟に扱えます。

まとめ

種類役割アクセス方法
通常のポインタ一般の変数のアドレスを保持*p
ダブルポインタポインタ変数のアドレスを保持**q
voidポインタ任意の型の変数のアドレスを保持型キャスト後に参照

ダブルポインタは2次元配列の操作や関数内でのポインタ書き換えなどに、voidポインタは汎用的な関数(例:mallocqsort など)の実装によく使われます。それぞれの特性を理解して使い分けると、C言語プログラミングの幅が大きく広がります。

  1. C言語におけるユニオンとポインタの使い方を徹底解説

    ユニオン(共用体)とは、異なるデータ型を持つ複数の変数が、同一のメモリ領域を共有するための仕組みです。構造体が各メンバーごとに独立したメモリを割り当てるのに対し、ユニオンではすべてのメンバーが同じアドレスを参照するという点が大きな特徴です。 ユニオンの構文 ユニオンを定義するときの基本的な書式は次の通りです。 union タグ名{ データ型 メンバー1; データ型 メンバー2; ---- ---- データ型 メンバーn; }; 実際の記述例を見てみましょう。 union sample{ int a; float b; char

  2. C言語のポインタ入門!宣言・初期化から配列アクセスの実例まで徹底解説

    ポインタ(pointer)とは、他の変数のメモリアドレスを格納するための変数です。C言語においてポインタは、メモリを直接操作したり、関数間でデータを効率的にやり取りしたりするために欠かせない重要な概念です。 ポインタの宣言・初期化とアクセス まず、次のような通常の整数変数の宣言を見てみましょう。 int qty = 179; 変数qtyには値「179」が格納されると同時に、メモリ上のどこかにその格納場所(アドレス)が割り当てられます。 ポインタの宣言 int *p; 「p」はポインタ変数であり、別の整数型(int)変数のアドレスを保持します。変数名の前にアスタリスク(*)を付けることで、「こ