KNキングの本の269ページでこの宣言に出くわしました
int a[ROWS][COLS], (*p)[COLS];
p = &a[0];
p
2 次元配列の最初の行を指すようになりました。a[0]
が 2 次元配列の最初の行を指す理由がわかりました。しかし、宣言の構文がわかりませんp
。それはどういう意味ですか、どうすれば覚えられますか?
周りの括弧は何をし*p
ていますか?(*p)
この構文は、演算子の優先順位に関して何を意味しますか?
KNキングの本の269ページでこの宣言に出くわしました
int a[ROWS][COLS], (*p)[COLS];
p = &a[0];
p
2 次元配列の最初の行を指すようになりました。a[0]
が 2 次元配列の最初の行を指す理由がわかりました。しかし、宣言の構文がわかりませんp
。それはどういう意味ですか、どうすれば覚えられますか?
周りの括弧は何をし*p
ていますか?(*p)
この構文は、演算子の優先順位に関して何を意味しますか?
[]
接尾辞と演算子はどちらも()
単項*
演算子よりも優先順位が高いため、最初にバインドされます。IOWT *p[N]
は次のように解釈されT *(p[N])
ます。p
へのポインタの配列ですT
。配列へのポインター (または関数へのポインター)を宣言するには、括弧を使用して、*
演算子を の前に強制的にバインドする必要があり[]
ます。
T *p[N]; // p is an array of pointer to T
T (*p)[N]; // p is a pointer to an array of T
T *f(); // f is a function returning pointer to T
T (*f)(); // f is a pointer to a function returning T
コンマを無視して、次のように書き直します。
int a[ROWS][COLS];
int (*p)[COLS];
p = &a[0];
p
大きなint の配列へのポインタですCOLS
。宣言はそれほど多くのメモリを割り当てませんが、いくつかの境界チェックを許可します。配列のメモリは次の宣言で割り当てられました:
a
=>int a[ROWS][COLS];
a[0] が 2 次元配列の最初の行を指す理由を理解しています
これはすでに不正確です。値のコンテキストでa[0]
は、実際には「2D 配列の最初の行」を指すわけではありません。実際には、2D 配列の最初の行の最初の要素a[0]
を指します。言い換えれば、in value contextは へのポインタです。おそらくご存知のように、の型は に崩壊します。そしてに等しい。したがって、実際には行全体を指しているわけではありません。孤立したオブジェクトを指しています。a[0]
a[0][0]
a[0]
int *
sizeof *a[0]
sizeof(int)
int
ここで、本当に 2D 配列の最初の行をポイントしたい場合、つまり行全体&a[0]
をポイントしたい場合は、 . これにより、 type のポインターが得られますint (*)[COLS]
。sizeof *&a[0]
は に等しいことに注意してくださいsizeof (int[COLS])
。したがって、これは実際には 2D 配列の最初の行へのポインターです。これがあなたの例に見られるものです。
数値的a[0]
に と&a[0]
(値コンテキストのポインタとして) は同じであることに注意してください。これらは線形メモリ内の同じ場所を指しているためです。ただし、タイプごと&a[0]
に行全体をa[0]
指しますが、単一の要素を指します。