簡潔な答え
指定された userMask は次のように宣言されます
int *userMask[3][4];
次にuserMask
type を持ちint*[3][4]
ます。これは、int へのポインターの 2 次元配列です。外側の次元のサイズは 3、内側の次元のサイズは 4 です。実際には、要素の型が である 3 要素の 1 次元配列にすぎません。要素の型が である別の 4 要素の 1 次元配列ですint*
。
手順の説明
だからあなたがするなら
userMask[2][maskElement][user]
次に、基本的に最初の 2 つのインデックスを使用して、2 次元配列から特定のポインターを選択します。
int * p = userMask[2][maskElement];
次に、次のようにして、そのポインターからオフセットされた int を選択します
p[user]
これでコードはすべてuserMask[2][maskElement][user]
.
有効な C コード
有効な C コードを使用してステップバイステップで実行するには (次の内容をまだすべて理解していなくても心配する必要はありません)。
int * userMask[3][4] = { { 0 } };
int ** pa = userMask[2]; /* int*[4] becomes int** implicitly */
int * pi = pa[maskElement];
int i = pi[user];
assert(i == userMask[2][maskElement][user]);
配列とポインタの違い
だから私はあなたに何か重要なことを示していると思います。上記の配列には、配列へのポインターが含まれていません。多くの C プログラマーが予期していない、それらの動作の違いを見てみましょう。
int array[5][4][3];
/* int[4][3] implicitly converts to int(*)[3] (pointer to first element) */
int (*parray)[3] = array[0];
int ** pint = (int**) array[0]; /* wrong!! */
では、 と を行うparray[1]
とどうなるでしょうpint[1]
か。1 つ目は parray をsizeof(int[3])
バイト単位で進め ( 3 * sizeof(int)
)、2 つ目はsizeof( int* )
バイト単位で進めます。したがって、実際には、最初のものは正しい配列を提供しますがarray[0][1]
、2番目のものは を提供します( char * )array[0] + sizeof( int* )
。これは、私たちが本当に望んでいない場所です。しかし、間違ったオフセットを取得することがすべてではありません。配列がアクセスされていることを認識していないため、 at をpint[1]
として解釈しようとしint*
ます。配列が で初期化されたとし0x00
ます。次に、アドレス 0x00 に基づいて次のインデックス ステップを実行します (pint[1][0]
たとえば実行中)。ああ、まったく未定義の動作です! そのため、違いを強調することが非常に重要です。
結論
これはあなたが要求した以上のものでしたが、これらの詳細を知ることは非常に重要だと思います. 特に、2 次元配列を関数に渡したい場合、この知識は非常に役立ちます。