LoginSignup
8
11

More than 5 years have passed since last update.

配列のポインタとポインタのポインタ

Last updated at Posted at 2019-01-25

配列のポインタというかポインタのポインタというかポインタでハマったので忘れないうちに簡単にまとめてみます。

配列のポインタとは

ポインタの配列ではなく配列のポインタ。
例えば

char hoge[] = "fuga";

と宣言します。
すると配列のポインタは&hogeです。

配列と配列のポインタ

ここで配列には配列のポインタが存在するので&hoge、すなわち配列のポインタを参照することができます。
ここでhoge&hogeのポインタを見てみると

  printf("hoge = %p\n", hoge);
  //=> hoge = 0061FF2B
  printf("&hoge = %p\n", &hoge);
  //=> &hoge = 0061FF2B

このようになります。

結局同じアドレスを指しています。
これは配列の先頭アドレスになるので結局配列のポインタも配列の文字列の先頭アドレスを指します。

じゃあ何が違うんだ!というと型が違います。
hogechar*型ですが&hogechar**型になります(訂正:追記参照)。
つまり型違いで同じアドレスを指しているわけです。


追記(1/25)

&hogechar**型ではありません。
配列のポインタ型であり、char* []型になります。

shiracamusさんコメントありがとうございました。

ポインタのポインタと配列のポインタ

私が陥った罠はこれです。
関数間で配列を受け渡すとき、配列のアドレスを仮引数で宣言したポインタへ受け渡します。
hogepiyoの引数として渡すと、

void piyo(char* foo)
{
  printf("foo = %p\n", foo);
  //=> foo = 0061FF2B
  printf("foo = %p\n", &foo);
  //=> foo = 0061FF10
}

このようになります。
配列のポインタと思い込んで&fooを参照したところ全く違うアドレスを参照してしまいました。

つまりこのときのfooは配列ではなくポインタであるため、&fooは配列hogeのポインタではなく配列hogeのアドレスを持ったポインタfooのポインタになります。
つまり配列とはまったく別物で、変数fooのアドレスを指しています。
ポインタを理解していないせいでここでハマりました…

ここで&foochar**型なので例えばchar* pにアドレスを渡すときは&foochar*型にキャストしなければ型が競合します。

ポインタとはアドレスを保持することのできる変数、と理解しておくとこのようなミスがなくなるのではと思います。

考察

ここからは考察になりますが、ポインタとはアドレスを保持することのできる変数、であり、*pのようなポインタの指す変数の中身を参照するときの挙動としては、保持している先のアドレスを参照し、そこにある値を見ているのではと思います。というかそれしか説明つかない…

おわりに

仮引数で宣言したポインタに配列を渡すときはアドレスが渡されていて配列は渡されているわけではないという理解が大事だったんだなぁと感じました。

8
11
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
11