4

C/C++ で、MD arr を受け取る func パラメータがすべてのサブ配列/次元のサイズを持つ必要があるのはなぜですか?

here(PDF): MD arrs の唯一の違いは、「コンパイラーが各虚数次元を記憶している」ことですが、これらの次元に違反すると、コンパイラーは何もしません。

char arr[3][5];
arr[0][5] = 10;

では、これらのサイズを覚えておく意味は何ですか?

4

2 に答える 2

7

配列へのインデックス付きアクセスでは、インデックス値と宣言された下位次元に基づいて、行優先の順序でメモリ オフセット計算を計算する必要があります。それについては後ほど詳しく説明します。

しかし、最初に、あなたの質問はこの単純な観察に密接に関連しています:

void foo( char a[] )
{
    a[5] = 'a';
}

// caller of foo() from somewhere
char arr[5];
foo(arr);

なぜコンパイラはそれを可能にするのですか?? これは C であり、未定義の動作で自分の足を撃ち落とす権利が完全にあるからです。これを念頭に置いてください:

void foo( char a[][5] )
{
    a[0][5] = 'a';
}

// caller of foo() from somewhere
char arr[4][5];
foo(arr);

これは、以前のコードと同じように「有効」です (つまり、自分のリスクと危険を冒して UB に入る権利があります)。この場合、それは「機能」しますが、これは、基礎となる配列の線形背景が 20 要素幅であり、6 番目の要素 (技術的にはarr[1][0].

これらの下位ディメンションの目的は、次のようにアクセスを適切に計算することです

void foo( char a[][5] )
{
    a[2][1] = 'b';
}

2上位インデックスは、適切な要素の線形オフセットを効果的に計算するために、宣言された下位ディメンション (この場合は ) を使用する必要があります5。2D 配列を 1D 線形ブロックに配置すると、これを行うために使用されます。

char arr[20]; // 4*5
arr[2*5+1] = 'b';

に注意してください5。宣言された劣位次元は、行の飛躍 (比喩表現) を適切に計算するために認識されている必要があります。

少なくとももう少し明確になることを願っています。

これが化合物であることに注意する必要があります。つまり、次のとおりです。

char arr[3][4][5];
arr[1][2][3] = 'c';

基礎となる配列の線形背景に対して正しい位置を効果的に計算します。

char arr[60]; // 3*4*5
arr[ 1*(4*5) + 2*(5) + 3 ] = 'c';

等々。あなたが望むだけ多くの次元にそれを取り出してください。これを適切に行うには、すべての下位次元を把握する必要があります。

于 2012-12-25T11:02:49.340 に答える
2

配列は特別な種類のオブジェクトではなく、単なる項目の長いリストです。あなたarr[3][5]は実際にはただの でarr[15]あり、コンパイラによってにarr[0][5]リダイレクトされます。arr[5]

C/C++ はサイズを格納しないため、[0][5]マップを[5]正しく作成するにはサイズをハードコーディングする必要があります。

一部のコンパイラは、[0][5]が間違っていることを強制する (または警告する) 場合がありますが、 にマップされるため[5]、少なくとも何かを行います。

于 2012-12-25T10:51:24.993 に答える