観測された動作は、固定サイズの配列と可変的に変更された配列で同じです。
#include <stdio.h>
int main(void)
{
enum { m = 3, n = 4 };
int a[m][n];
int (*p)[m][n] = &a;
printf("p : %p, *p : %p, **p : %p\n", p, *p, **p);
return(0);
}
私のマシンでは、これにより次のものが生成されました。
p : 0x7fff6c542520, *p : 0x7fff6c542520, **p : 0x7fff6c542520
もちろん、p
は両方のプログラムの 2D 配列へのポインターです (また、「両方のプログラムで」修飾子は適用されますが、再度追加するつもりはありません)。を印刷p
すると、それに割り当てられている配列のアドレスが得られます。これは のアドレスですa
。p
は 2D 配列へのポインターであるため、2D 配列は' *p
is' ですが、ほとんどの場合、配列参照は最初の要素へのポインターになるため、参照と同じメモリ位置である*p
へのポインターになります。同様に'is' は 1D 配列ですが、同様にへのポインタであり、参照と同じメモリ位置でもあります。したがって、3 つの値は同じであるはずであり、コンパイラはそれを正しく取得します。a[0]
a
**p
**p
a[0][0]
a
それは簡単に読めるものではありませんが、説明しようとしているのは C でもありません。
p
以下は、*p
とが指すさまざまなオブジェクトのサイズを示す元のプログラムのマイナー バリエーションです**p
。
#include <stdio.h>
int main(void)
{
enum { m = 3, n = 4 };
int a[m][n];
int (*p)[m][n]=&a;
printf("p+0 : %p, (*p)+0 : %p, (**p) + 0 : %p\n",
(void *)(p+0), (void *)((*p)+0), (void *)((**p)+0));
printf("p+1 : %p, (*p)+1 : %p, (**p) + 1 : %p\n",
(void *)(p+1), (void *)((*p)+1), (void *)((**p)+1));
return(0);
}
厳密には、%p
変換指定にはvoid *
;を指定する必要があります。ここのキャストはそれを強制します。元のコードは公式には少しずさんですが、問題になるマシンはほとんどありません。
これからの出力は次のとおりです。
p+0 : 0x7fff63453520, (*p)+0 : 0x7fff63453520, (**p) + 0 : 0x7fff63453520
p+1 : 0x7fff63453550, (*p)+1 : 0x7fff63453530, (**p) + 1 : 0x7fff63453524
+1
バージョンで表されるように、指しているオブジェクトのサイズがどのように異なるかに注意してください。
sizeof(*p) = 0x30
sizeof(**p) = 0x10
sizeof(***p) = 0x04