
ポインタ変数へのポインタについて、概念を例とあわせて確認していきましょう!
ポインタへのポインタは、ダブルポインタ(二重のポインタ、double pointer)と読ばれることもあります。
ただ、ダブルポインタと発音すると、「double *」と勘違いされることもありますが、これはまったく違うものなのでご注意ください。
その意味の通り、ポインタ変数へのポインタのことで、下のように宣言されます。
int **pointer;
ポインタの識別子である記号「*」が変数の前に2つくっついてます。
ポインタへのポインタ変数、通常のポインタ変数、通常の変数の関係を図で見てみましょう。
#include <stdio.h>
int main(){
int hp = 100;
int *p1 = &hp;
int **p2 = &p1;
printf("hp を変数から確認: %d。アドレスは %d\n", hp, &hp);
printf("p1 から hp を確認: %d。アドレスは %d\n", *p1, p1);
printf("p2 から hp を確認: %d。アドレスは %d\n", **p2, p2);
}
実行結果は下のようになり、3つの方法で変数 100 の中身を確認できました。
hp を変数から確認: 100。アドレスは 6684180
p1 から hp を確認: 100。アドレスは 6684180
p2 から hp を確認: 100。アドレスは 6684180
関係は下のようになります。
hp の中身が格納されているメモリアドレスへは 「hp」、「*p1」、「**p2」のいずれでもアクセス可能で、同じ結果になります。
みたいな感じですね。
データ同士をつなぎ合わせる時には、ポインタを使って紐づけることが出来ます。
メモリアドレスを集めて、データ同士の関係を定義することがあります。
例えば、ぷらんくちゃんの持っている袋「bagA」には3つのアイテムが収納できるとします。 この3つの収納場所に、それぞれアイテムデータへのポインタが入っていることを考えてみましょう。
収納場所B,C,Dはそれぞれ、アイテムデータへのポインタを持っています。
格納場所Bは「毒キノコ」へのポインタ、 格納場所C,Dは「穴あきチーズ」へのポインタを格納しています。
このような構造であるとき、袋Aの、格納場所Cには下のような形でアクセスできます。
#include <stdio.h>
int main() {
char const poison_mushroom[64] = "毒キノコ";
char const cheese[64] = "穴あきチーズ";
char *bagA[3]; // バッグに 3 つアイテムが入る
bagA[0] = &poison_mushroom; // バッグの1つ目は毒キノコ
bagA[1] = &cheese; // バッグの2つ目は穴あきチーズ
bagA[2] = &cheese; // バッグの3つ目は穴あきチーズ
char** planc_equip[5]; // 5 つ装備できる
planc_equip[0] = &bagA; // 袋を装備させる
printf("ぷらんくちゃんが装備している袋Aの 2 番目には %s が入っています。\n", *((*planc_equip)+1) );
}
実行すると下のような結果となります。
プレイヤーが装備している袋の 2 番目には 穴あきチーズ が入っています。
まず、袋A には、3つのアイテムへのポインタがあり、 それぞれアイテムデータ(今回はアイテムの名前を表す文字列データ)へのポインタを代入しています。
char *bagA[3]; // バッグに 3 つアイテムが入る
bagA[0] = &poison_mushroom; // バッグの1つ目は毒キノコ
bagA[1] = &cheese; // バッグの2つ目は穴あきチーズ
bagA[2] = &cheese; // バッグの3つ目は穴あきチーズ
また、ぷらんくちゃんの装備を表す planc_equip は、5つの装備をすることができます。今回は袋Aのみ装備させる設定とします。
char** planc_equip[5]; // 5 つ装備できる
planc_equip[0] = &bagA; // 袋を装備させる
plang_equip[0] には袋Aを装備させたいので、袋Aへのポインタアドレスを代入しています。
このとき、planc_equip 変数はポインタへのポインタとして定義することになります。
printf("ぷらんくちゃんが装備している袋Aの 2 番目には %s が入っています。\n", *((*planc_equip)+1) );
最後に、袋A の添え字[1] (つまり袋Aの中の 2 番目のアイテム)に格納されているアイテムデータにアクセスします。
*planc_equip は、 planc_equip に入っているポインタアドレスの先データを表しますので、これは bagA の先頭アドレス(つまり bagA[0] のアドレス)を示しています。
*planc_equip は bagA、もしくは &bagA[0] と置き換えられます。(実際、このように書き換えても同じ結果が得られます)
*(bagA + 1) は配列 bagA を 1 つの(char *)ぶんずらしたポインタアドレスへのアクセスを意味します。つまり、bagA[1] へアクセスしたのと同じ結果が得られます。
このようにしてポインタへのポインタを使うことで、 ぷらんくの装備[0] のポインタから、袋A にアクセスし、 袋A[1] のポインタからアイテム「穴あきチーズ」にアクセスすることができました。
C言語に近い、プログラミング言語の C++ では、ポインタへのポインタを基本的に使う必要がないよう、標準ライブラリも工夫されています。 ポインタへのポインタは C++ でも使うことはできますが、そもそも読みづらいしバグの原因に繋がりやすいのでなるべく避けた方が良いでしょう。
コメント、ありがとうございます。
ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。
Twitter:@NodachiSoft_jpお名前:以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください
お名前: