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

C言語におけるポインタのポインタという概念について解説します。
ポインタのポインタは、通常のポインタ変数がメモリ上のアドレスを保持することができるように、さらにそのアドレスを指す別のポインタ変数を定義することができます。
この記事では、その使い方や注意点などを詳しく解説していきます。
ポインタのポインタとは?
ポインタのポインタとは、2重の間接参照を行うための仕組みです。
通常、ポインタ変数はあるデータ型のアドレスを格納する変数であり、その値が指し示す先にある実際のデータにアクセスすることができます。
しかし、ポインタ変数にもアドレスが存在し、そのアドレスを格納する変数のことをポインタのポインタといいます。
このような構造は初見ではやや複雑に感じられるかもしれませんが、例えば多次元配列を扱ったり動的メモリ確保時に便利な場合もあります。
また、関数内部で引数として渡された変数自体を書き換えたい場合などでも使用されます。
ポインタのポインタの使い方
宣言
ポインタのポインタを宣言する場合は、単純なポインタ宣言に加えて「*」演算子をさらに一つ追加します。例えばint型への二重間接参照用の変数ptr2が必要な場合、以下のように宣言します。
int **ptr2;
代入・参照
次に、値やアドレスを代入したり参照したりする方法です。まずは値を代入する例です。
int a = 10;
int *p1 = &a; // p1はaへの単一間接参照用
int **p2 = &p1; // p2はp1への二重間接参照用
printf("%d\n", **p2); // 出力結果:10
上記コードでは、「**p2」でaが指し示されます。また、「&」演算子でアドレス取得も可能です。
//すべてaのアドレスが表示される
printf("%x\n", &a);
printf("%x\n", p1);
printf("%x\n", *p2);
関数での使用
関数内部でもポインタのポインタを扱えます。以下はswap関数内で引き渡された整数型変数a,bそれぞれが持つ値を交換する処理例です。
#include <stdio.h>
#include<stdlib.h>
void swap(int** pptr_a, int** pptr_b) {
int tmp_ptr;
tmp_ptr = **pptr_a;
**pptr_a = **pptr_b;
**pptr_b = tmp_ptr;
}
// 使用例:
int main() {
int a = 3, b = 5;
int* ptr_a = &a;
int* ptr_b = &b;
printf("before: %d %d \n", a, b);
swap(&ptr_a, &ptr_b);
printf("after : %d %d \n", a, b);
}
before: 3 5
after : 5 3
int型やchar型などの基本のデータ型であればポインタのポインタを使うことは少ないですが、複雑なデータ構造や多次元配列等では扱いやすくなるため便利です。
ただし過度な使用や混乱招く書き方等注意点もあります。
ポインタのポインタを使うメリットとデメリット
ポインタのポインタは、C言語において非常に重要な概念ですが、扱いには注意が必要です。
ここではポインタのポインタを使用するメリットとデメリットを見ていきましょう。
ポインタのポインタを使うメリット
1. 関数内で変数を書き換えることができる
関数内で引数として渡された変数を書き換えたい場合、その変数へのアドレスを渡す必要があります。
しかし、単純なポインタだけでは関数外で宣言された変数へのアドレスしか渡せません。そこで、ポインタのポインタを使用することで、関数内部からも関数外部にある任意の変数へアクセスすることが可能になります。
2. 動的メモリ確保時に便利
動的メモリ確保時(malloc, calloc等)は、確保した領域への先頭アドレスが返ってくるため、その先頭アドレスを指す一次元配列用の単純なポインタだけでは不十分な場合があります(二次元以上の配列など)。
ですが、ポインタのポインタを扱うことで、二次元配列や多次元配列用に複雑な構造体型式においても柔軟に動的にメモリを確保して処理できるようになります。
ポインタのポインタを使うデメリット
1. 読み取りやすさが低下する
通常よりも多層化されたコードは読み取りやすさが低下し易くなります。また、「*」演算子(星マーク)記号付き「int *p;」形式等よりも更に複雑化しています。
2. バグ発生率増加
通常よりも多層化されたコードはバグ発生率増加し易くなっています。「NULL」値設定忘れだけでもエラー発生原因特定困難性上昇します。
以上からわかるように、プログラム開発者自身判断力及び経験値向上度合い次第ですが、確実に通常のポインタint *p
とりも更に複雑化しています。
まとめ
ポインタのポインタは、C言語において重要な概念の一つです。ポインタを使うことで、メモリ上のデータにアクセスすることができますが、その中でもポインタのポインタを使うことでより高度なプログラミングが可能になります。
初心者には少々難解ですが、しっかり理解しておくことでより効率的なプログラム作成が可能になるため、ぜひ学習してみてください。