25

一部のコードを変更していて、理解できない宣言に出くわしました。

int *userMask[3][4] = {0};

これは一体何を指しているのでしょうか?すべての要素がポインタである行列ですか? それともサイズ [3][4] の行列を指していますか?

ありがとう


私の質問は、userMask[2][maskElement][user]として宣言されているときにどのように機能するかだと思いintます。int[]それが正しく機能するためには、userMask が必要ではないでしょうか。私はこの権利を理解していないに違いない...

余談ですが、cdecl Robert についてご提案いただきありがとうございます。しかし、XPコマンドプロンプトでそれを使用する方法を知っている人はいますか? 私が得ることができるのは構文エラーです:(

4

9 に答える 9

42

簡潔な答え

指定された userMask は次のように宣言されます

int *userMask[3][4];

次にuserMasktype を持ち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 次元配列を関数に渡したい場合、この知識は非常に役立ちます。

于 2008-11-08T17:02:19.380 に答える
18

これは、各要素が へのポインターである 2 次元配列でありint、すべてのポインターはゼロに初期化されます。

フォローアップでは、配列が次のように使用されていることを示しています。

if(userMask[2][maskElement][user] && blah)
    result = true;

この場合、 の各要素userMaskは実際には の配列を指す必要がありintます。( anは、単一または の配列をint*指すことができます)。これを判断するには、 に値を割り当てるコードを確認してください。たとえば、次のように書くことができます。intintuserMask

int userArray[2] = { 10, 20 };

userMask[0][0] = userArray; // userMask[0][0] points to the
                            // first element of userArray.

次に、次のコードは にインデックスを付けますuserArray:

int value = userMask[0][0][1]; // sets value = userArray[1], giving 20.
于 2008-11-08T16:07:33.280 に答える
11
int *userMask[3][4] = {0};

各メンバーが int へのポインターである 2 次元配列です。さらに、すべてのメンバーが null ポインターに初期化されます。

int (*userMask)[3][4];

int の 2 次元配列へのポインタになります。C の大括弧は * よりも強く結合するため、配列へのポインターを作成するには括弧が必要です。

cdecl複雑な宣言を説明するためにダウンロードできるシンプルなユーティリティです。

cdecl> explain int *userMask[3][4]
declare userMask as array 3 of array 4 of pointer to int

逆のこともできます。

cdecl> declare userMask as pointer to array 3 of array 4 of int
int (*userMask)[3][4]
于 2008-11-08T16:14:56.823 に答える
3
if(userMask[2][maskElement][user] && blah)
   result = true;

ここでの 2 番目の部分は、C には配列がないということです。ポインター演算しかありません。定義により、常にsop[i]と同等です*(p+i)

userMask[2][maskElement][user]

と同等です

*((userMask[2][maskElement])+user)

コードはどこかでその配列のポインターにベクトルを割り当てています (それは malloc(3c) または同様の呼び出しによるものだと思います)。今あなたのifは言っています

userMask [2][maskElement] のベクトルのユーザー番目の要素がゼロでない場合

THEN IF blah is non-zero (&& の短絡評価のため、最初の結合が 0 の場合、2 番目の結合は評価されません)

次に、結果を true に設定します。

于 2008-11-08T17:45:15.610 に答える
2

インサイドアウトのルールを適用します。

int *userMask[3][4] = {0};

宣言のinnerpost部分から始めて、

userMask

名前です

userMask[3] 

そのうちの 3 つ (のベクトル) にスペースを割り当てます

userMask[3][4] 

userMask[3]4のスペースを割り当てます

int *

userMaskアイテムがポインタ型であることを示しますint

そして、= {0}すべての要素が であるイニシャライザです0。そう

int *userMask[3][4] = {0};

int * の 3x4 配列で、0 に初期化されます。

于 2008-11-08T17:34:39.907 に答える
0

ステートメントは usermask 配列の 3 行目にアクセスし、次にその行の maskElement 番目のポインターにアクセスすると思います。これは int ポインターであるため、int 配列 (文字列と考えてください) の先頭を指すことができます。それが行われており、その配列がユーザーによってサブインデックス付けされていると仮定します。

于 2008-11-08T16:23:24.573 に答える
0

userMask[2]はタイプint*[]
userMask[2][maskElement]あり、タイプint*
あり、タイプでもuserMask[2][maskElement][user]ありintます。

宣言

int *userMask[3][4] = {0};

の省略形です

int *userMask[3][4] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};

ここで、各ゼロは暗黙的に に変換され(int*)0ます。

于 2008-11-08T16:27:06.033 に答える
0

次のように読むと役立ちます。

type variablename[array_spec];

この場合: int* usermask[3][4];

したがって、int* の行列です。

現在、c はポインターと配列を区別しないため、ポインターで配列インデックスを使用できます。

int* i;
int the_int_behind_i = *(i+1);
int also_the_int_behind_i = i[1];

もちろん、配列のように、いくつかの int が互いに後ろに並んでいる領域を指す必要があります。

最後の例で使用されているインデックス operator[] は、最初の array_spec のように見えますが、この 2 つはまったく異なることに注意してください。

つまり: userMask[2][maskElement][user]

[2][maskElement] に格納されているユーザーマスク ポインターを選択し、それをユーザーuserに対して評価します。

于 2008-11-08T17:02:27.710 に答える
-1

これは、すべての要素がポインターである行列です。

サイズが [3][4] の行列を指している場合、コードは次のようになります。

int userMask[3][4]={0};
于 2008-11-08T16:09:10.907 に答える