記事には広告を含む場合があります。

C言語入門講座

【C/C++】ポインタのポインタとは?メリットは?配列・引数における使い方

おゆ

組み込み系プログラマとして5年働いていた元エンジニアです。得意言語はC言語とC++。本サイトでは学生および新人組み込み系プログラマに向けてプログラミング知識をわかりやすく解説しています。

ポインタのポインタ(ダブルポインタ)とはポインタを示すポインタです。

詳しくは以下で図を使って解説します。

ポインタのポインタは配列のポインタ渡しの際などに使えます。

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

ポインタには変数のアドレスが格納されますよね。

参考【C言語】アドレスとポインタをわかりやすく解説!使うメリットは?

ポインタって何?使うメリットは?わかりやすく教えてほしい。 アドレスって何?ポインタに関係あるの?メモリのアドレスって言われてもピンとこない… こんなお悩みにお答えします。 アドレスとはメインメモリ上 ...

続きを見る

ポインタのポインタ(ダブルポインタ)にはポインタのアドレスが格納されます。

例えばある変数aはメモリアドレス100の位置に値10が格納されているとします。(アドレスは適当です。)
ポインタのポインタ

aのポインタをpとするとpにはaのアドレス100が格納されます。

ポインタpのポインタをppとするとppにはpのアドレス200が格納されます。

このppはpというポインタを示すポインタ、つまりポインタのポインタと呼ばれます。

ポインタのポインタの使い方

ポインタのポインタの使い方

定義:
データ型 **ダブルポインタ名;

定義と初期化:
データ型 **ダブルポインタ名=&ポインタ名;

代入:
ダブルポインタ名=&ポインタ名;

例1:

#include <stdio.h>
void main()
{
    int num=10;
    int *p=&num;
    int **pp=&p;

    printf("*p=%d\n",*p); //=num
    printf("p=%u\n",p); //=&num
    printf("&p=%u\n",&p);
    
    printf("**pp=%d\n",**pp); //=*p=num
    printf("*pp=%u\n",*pp); //=p
    printf("pp=%u\n",pp); //=&p
    printf("&pp=%u\n",&pp);
}

実行結果

*p=10
p=1501559628
&p=1501559616
**pp=10
*pp=1501559628
pp=1501559616
&pp=1501559608

アドレス値は非常に大きな値を取るため、正しい値を出力するために符号なし整数のフォーマット指定子%uを使っています。

おゆ
ちなみにポインタのポインタのポインタ(トリプルポインタ)も存在しますが、実務で使うことはないと思うのでダブルポインタを抑えておけばOKです。

ポインタのポインタを使うメリット・使いどき

配列をポインタ渡しするとき

ポインタのポインタは配列を引数としてポインタ渡しするときに使えます。

配列をポインタ渡しをすると仮引数(関数作成時に定義する引数)の値の変更を関数外に引き継げます。

以下の例ではGetHello関数の仮引数ptrに「Hello」が代入され、その値が実引数(関数呼び出し時に渡す引数)arrayに引き継がれます。

例2:

#include <stdio.h>
void GetHello(char **ptr)
{
    *ptr="Hello"; //配列の先頭アドレスarrayを文字列
    printf("*ptr=%s\n",*ptr); //=array
    printf("**ptr=%c\n",**ptr); //=*array
    printf("*((*ptr)+1)=%c\n",*((*ptr)+1)); =//*(array+1)
}
void main()
{
    char *array;
    GetHello(&array);
    printf("array=%s\n",array);
    printf("*array=%c\n",*array);
    printf("*(array+1)=%c\n",*(array+1));
}

実行結果

*ptr=Hello
**ptr=H
**(ptr+1)=e
array=Hello
*array=H
*(array+1)=e

GetHello関数内の1行目で*ptr(=array)に文字列Helloの先頭アドレス(Hが格納されているメモリのアドレス)が格納されます。

そのため**ptr(=*array)を出力するとHが得られます。

次の文字eが格納されているアドレスはarray+1のように表されるので、*(array+1)を出力するとeが得られます。

同じように*(array+2)からはl、*(array+4)からはoが得られます。

ポインタのポインタであるptrはポインタarrayを指しているので、**ptr=*array、*ptr=arrayが成り立ちます。

それぞれに格納された値とメモリアドレスの関係は以下のようになります。(アドレスは適当です。)
配列のポインタ

関数内でポインタのアドレスを変更するとき

実引数として渡したポインタのアドレスを関数内で変更したい場合にはポインタのポインタが使えます。

例3:

#include <stdio.h>
int num=10;
void GetNum(int **ptr)
{
    *ptr=&num;
}
void main()
{
    int *i=0;
    GetNum(&i);
    printf("*i=%d\n",*i);
}

実行結果

*i=10

C言語で行き詰まったら…

C言語・C++がわからない時に質問できるサイト・サービス5選

C言語を独学で勉強しているけど内容がイマイチわからない。もはや何がわからないのかもわからない。 C++のエラーが解決できない。ググってもわからない。わかる人に解説してほしい。 こんなお悩みにお答えしま ...

続きを見る

ブログランキング参加中。クリックしてもらえると励みになります。

ブログランキング・にほんブログ村へ

-C言語入門講座