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

C言語入門:ポインタ配列とポインタへのポインタ(二重ポインタ)の基本をわかりやすく解説

はじめに

C言語において、ポインタはメモリを直接扱える強力な機能です。本記事では、その応用形である「ポインタ配列」と「ポインタへのポインタ(二重ポインタ)」について、宣言方法・初期化方法・値へのアクセス方法を、サンプルコードと実行結果とともに順を追って解説します。

ポインタ配列とは

通常の変数と同様に、ポインタも配列として宣言することができます。これを「ポインタ配列」と呼びます。各要素がそれぞれ別のアドレスを保持できるため、複数のデータを間接的に扱う際に便利です。

宣言方法

データ型 *ポインタ名 [サイズ];

例えば、次のように宣言します。

int *p[5]; // int型の要素アドレスを5つ格納できるポインタ配列

この場合、p は「int型変数のアドレス」を5個格納できる配列になります。

初期化方法

ポインタ配列の初期化には、アドレス演算子「&」を使用します。配列 a の各要素のアドレスを、ポインタ配列 p の各要素に代入する例を見てみましょう。

int a[3] = {10, 20, 30};
int *p[3], i;

for (i = 0; i < 3; i++)
    p[i] = &a[i];   // 各要素のアドレスを代入
// または、配列名が先頭アドレスを表す性質を利用して
for (i = 0; i < 3; i++)
    p[i] = a + i;   // p[i] = &a[i] と同じ意味

値へのアクセス

ポインタが指す先の値を取得するには、間接演算子(デリファレンス演算子)「*」を使用します。

for (i = 0; i < 3; i++)
    printf("%d", *p[i]);

サンプルプログラム

#include <stdio.h>

int main(void) {
    int a[3] = {10, 20, 30};
    int *p[3], i;

    for (i = 0; i < 3; i++)
        p[i] = &a[i];   // 配列要素のアドレスで初期化

    printf("配列の要素: ");

    for (i = 0; i < 3; i++)
        printf("%d \t", *p[i]);   // ポインタ配列経由で表示

    return 0;
}

実行結果

配列の要素: 10  20  30

ポインタへのポインタ(二重ポインタ)とは

「ポインタへのポインタ」とは、別のポインタ変数のアドレスを保持する変数のことです。一般に「二重ポインタ」とも呼ばれます。イメージとしては、「変数 a → ポインタ p → ポインタ q」というように、2段階の間接参照が行われる構造になります。

宣言方法

データ型 **ポインタ名;

例えば、次のように宣言します。

int **p; // p はポインタへのポインタ

「*」が2つ付いている点に注目してください。これは「ポインタのアドレスを格納する」ことを意味します。

初期化方法

こちらも初期化にはアドレス演算子「&」を使用します。変数 a のアドレスをポインタ p に、さらにポインタ p のアドレスを二重ポインタ q に代入します。

int a = 10;
int *p;
int **q;

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

値へのアクセス

値を取り出す際は、間接演算子「*」を使います。二重ポインタの場合は「**」と2回適用することで、最終的な変数の値にたどり着きます。

  • a … 変数そのものの値
  • *p … ポインタ経由で a の値を参照
  • **q … ポインタへのポインタ経由で a の値を参照

サンプルプログラム

#include <stdio.h>

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

    p = &a;   // aのアドレスをpへ
    q = &p;   // pのアドレスをqへ

    printf("a = %d\n", a);
    printf("ポインタ経由のaの値 = %d\n", *p);
    printf("二重ポインタ経由のaの値 = %d\n", **q);

    return 0;
}

実行結果

a = 10
ポインタ経由のaの値 = 10
二重ポインタ経由のaの値 = 10

まとめ

ポインタ配列は「複数のアドレスをまとめて管理できる配列」、ポインタへのポインタは「ポインタ自体のアドレスを保持する変数」です。いずれも間接演算子「*」によって実際の値へアクセスできます。二重ポインタは、文字列の配列(char *argv[] など)や、関数内でポインタの中身を書き換えたい場面など、実践的なプログラムでも頻繁に登場する重要な概念なので、しっかり理解しておきましょう。

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

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

  2. C#のクラスとは?基本概念からコンストラクタまで徹底解説

    C#におけるクラスは、最も重要な型の一つです。クラスは、問題領域に関連するオブジェクトを生成するための「設計図」と考えることができます。つまり、クラスはテンプレートであり、そこからオブジェクトを作成します。クラスには、そのクラスから作られるオブジェクト群が共有する構造(データ)と振る舞い(メソッド)が定義されています。たとえるなら、クラスは「クッキーの型」であり、オブジェクトはその型で作られた「クッキー」そのものです。 カプセル化という重要な概念 クラスは、オブジェクト指向プログラミングにおける重要な概念である「カプセル化」を実現します。カプセル化とは、データと、そのデータを操作する処理を一箇