C言語やC++での多重ポインタはなかなかイメージがし辛いのですが…
①ポインタはデータを格納するアドレスを示す。 ②ポインタのポインタは①が入っているアドレスを示す。 ③ポインタのポインタのポインタは②が入っているアドレスを示す。
要するに下の図の状態で表されます。
このとき、A、*p、**dp、***tpはすべて同じ「7」を出力します。
多重ポインタが必要になる場面
多次元配列を扱う際に、複数のポインタを活用すると良いです。1次元配列であれば普通のポインタ。2次元配列であればポインタのポインタ。3次元配列であればポインタのポインタのポインタで表現することができます。メリットとしては、配列のサイズが不明な場合に多次元配列をメソッドの引数として指定できるなどがあります。
配列要素の表現方法
配列とポインタを使った表現の対応は次のとおりです。
1次元配列の場合(int *p)
p[i]=*(p+i)
2次元配列の場合(int **p)
p[i][j]=*(*(p+i)+j)
3次元配列の場合(int ***p)
p[i][j][k]=*(*(*(p+i)+j)+k)
どういうことだってばよ?
たとえば2次元配列の場合、次の図のように2次元配列を格納したアドレス空間を考えます。
int **p;
このとき、604番地に保存している25の値を取得するためには次のように指定してあげればよいです。
*(*(p+1)+2)
順番に見ていくと…イメージしやすいかと思います(番地が2ずつずれているのは、ここでのint型が2byteの大きさだからです)。
p:500
*p:550
p+1:502
*(p+1):600
*(p+1)+2:604
*(*(p+1)+2):25
ちなみに**pを言い換えると*(*(p+0)+0)であり、上の図でいう550番地に格納されている値を出力します。
通常の多次元配列の定義
多次元配列が定義された時、連続したメモリが確保されます。たとえば2次元配列a[X][Y]が定義された時、a[0][0],a[0][1],…a[0][Y],a[1][0],a[1][1],…a[X][Y]の順で各値をメモリに確保します。
下の例の場合Aはメモリの開始値のある500番地を保持し、A+1は508、*(A+1)+2は512を指します。A[1][2]の値をポインタから指定する場合は、*(*(A+1)+2)としてあげればよいです。
ポインタを使いこなすと2次元配列を1次元配列として扱うこともできます。
int x[3][2]; p = (int *)x;
x[i][j] と p[(i×k)+j] は、同じ場所を指します。(kは列の数、例の場合2)
さらに、配列の途中から1次元配列を指定することもできます。
int *p = &x[1][0];
3次元配列も同様の記述で1次元配列として参照することができます。
int x[4][3][2]; int *p = (int *)x;
上で定義した 3 次元配列の場合、x[i][j][k] と p[((i*3)+j)*2+k] が同じ場所を指すことになります。