見出し画像

c言語のダブルポインタについて理解しようとしてみた

c++を勉強していてポインタが2つ並ぶものを見て、なんだこれはと思いググって偶然teratailの過去の質問を見た。そこで説明されているコードが理解できず、理解したかったので自分なりのメモ。

※僕の解釈が間違ってるかもしれないので注意。

見たteratailの内容はこちら。


見たコード

int aloc_func(int sz, char **ppc)
{
  int err = 1;
  *ppc = (char *)malloc(sz);
  if (*ppc != NULL) {
    err = 0;
  }
  return(err);
}
void func()
{
  char *pc;
  int err;
  err = aloc_func(10, &p);
  if (err == 0) {
    // p を使う処理
    free(p);
  }
}


int aloc_func(int sz, char **ppc)の処理
int szは整数の引数を入れてくださいという意味。
char **ppcは、型はchar型のポインタchar *を格納するためのポインタを用意してくださいという意味。

すでにアドレスが確保してあるポインタchar *があって、そのポインタを格納するためのポインタを引数として持ってくるという意味。


aloc_func()のスコープの範囲外で定義した関数であるvoid func()関数を実行すると、void func()でaloc_func()を使っているので呼ばれて、int sz, char **ppcに該当する引数がvoid func()から渡され、aloc_func()内の

*ppc = (char *)malloc(sz);が実行され*ppcにメモリが確保される。

*ppcに確保したメモリも保持されてvoid func()に返される。

*ppc = (char *)malloc(10);を実行した結果
型はchar型のポインタ、容量10バイト確保。10バイト分確保されたメモリのアドレスはどんなものになるかは分からないので、0x1000になったとする。

このままでは*ppcは定義(初期化)だけされた状態なので、void func()内にそのままでは渡せない。aloc_func()の結果として渡すためには、*ppcアドレス、すなわち10バイト確保したアドレス0x1000のchar *を入れるための変数が必要になる。そこで用意するのがchar *を入れるためのポインタchar **。

*ppc、すなわちアドレス0x1000に確保した10バイトのchar *がchar **ppcというダブルポインタによって参照されvoid func()に返されることになる。

また、aloc_func()を実行した結果、戻り値としてerrの値は0か1を返す。
errが0はメモリを確保できた。errが1ならメモリがnullで確保できていないという意味。


*ppc = (char *)malloc(sz)ではポインタの定義(初期化)をしている
ポインタ変数ppcにmalloc関数でchar型のデータを入れるためのメモリをszバイト確保することで初期化。値はないけど、szバイト分入れる箱だけ確保した状態。

void funcの処理

void func()内のerrの値はaloc_func()の戻り値で、0か1となる。

errの値に応じて、void func()内の処理を分けている。

errが0ならメモリを確保できているので、メモリに値を代入するなどの処理を行い、処理が終わったらメモリをfreeで開放する。


void func()内のerr = aloc_func(10, &p);の流れ。

err = aloc_func(10, &p);を実行→aloc_func(int sz, **ppc)が呼ばれる。
→int sz = 10; **ppc = &p
→*ppc = (char *)malloc(sz); → *ppc = (char *)malloc(10);
→*ppc用のメモリが10バイト分確保される。
→err = 0;
→void func()関数にreturnされるもの
 err = 0; と*ppcの値を参照する**ppc=&pがvoid func()に返される。

流れとしてはvoid func()からaloc_func()を呼び出しているようにみえるけど、aloc_func()でリターンされる*ppc→**ppc→void func()の&pで10バイトのアドレス0x1000を受け取るという流れになっている。

&pでaloc_func()からアドレス0x1000に10バイトをうけとったので、void func()内で後ろの方の処理で使われているpはアドレス0x1000に10バイト分のメモリ領域を確保している状態となり、pに値を入れたりといった処理ができるようになる。


まとめ(感想)

以上ですが、理解しようとした実感としては、初めてなのもあってか、かなりややこしい印象。なのでダブルポインタ以上はほとんど使われることが無いのかもとおもいました。

この記事が気に入ったらサポートをしてみませんか?