web-dev-qa-db-ja.com

2D配列はダブルポインタですか?

int main()
{
    matrix[2][4] = {{11,22,33,99},{44,55,66,110}};
    int **ptr = (int**)matrix;
    printf("%d%d",**matrix,*ptr);
}

ただし、2次元配列がパラメーターとして渡されると、(* matrix)[2]に型キャストされます。コンパイラはこの配列をどの型として保存しますか... 2次元配列またはダブルポインターとして保存しますかまたは配列へのポインタ..配列として格納する場合、上記のような異なる状況でどのように異なる解釈をしますか。理解してください。

37
Angus

2D配列はダブルポインタですか?

いいえ。プログラムの次の行は正しくありません。

_int **ptr = (int**)matrix;
_

この回答は同じトピックを扱っています

多次元配列の実装方法を具体的なイメージにしたい場合:

多次元配列の規則は通常の配列の規則と変わらず、「内部」配列型を要素型に置き換えるだけです。配列項目は、メモリに次々に直接保存されます。

_matrix: 11 22 33 99 44 55 66 110
        -----------               the first element of matrix
                    ------------  the second element of matrix
_

したがって、要素_matrix[x][y]_に対処するには、_the base address of matrix + x*4 + y_を使用します(4は内部配列サイズです)。

配列が関数に渡されると、配列は最初の要素へのポインターに減衰します。お気づきのように、これはint (*)[4]になります。型の_4_は、コンパイラに内部型のサイズを通知します。これが機能する理由です。同様のポインターでポインター演算を行うと、コンパイラーは要素サイズの倍数を追加するため、_matrix_ptr[x][y]_の場合、_matrix_ptr + x*4 + y_を取得します。これは上記とまったく同じです。

したがって、キャストptr=(int**)matrixは正しくありません。一度、_*ptr_は、マトリックスのアドレスに格納されたポインター値を意味しますが、何もありません。第二に、プログラムのメモリのどこにも_matrix[1]_へのポインタがありません。

注:この投稿の計算では、不要な複雑さを避けるために、sizeof(int)==1を想定しています。

40
jpalecek

いいえ。多次元配列はメモリの単一ブロックです。ブロックのサイズは、次元の積に要素の型のサイズを掛けたものであり、ブラケットの各ペアのインデックスは、残りの次元の次元の積によって配列にオフセットされます。そう..

int arr[5][3][2];

30個のintsを保持する配列です。 arr[0][0][0]は1番目、arr[1][0][0]は7番目(3 * 2のオフセット)を提供します。 arr[0][1][0]は3番目(2によるオフセット)を提供します。

配列が減衰するポインターは、レベルに依存します。 arrは3x2 int配列へのポインターに減衰し、arr[0]は2要素のint配列へのポインターに減衰し、arr [0] [0]はintへのポインターに減衰します。

ただし、ポインターの配列を使用して多次元配列として扱うこともできますが、各ポインターをその配列に設定する必要があるため、追加のセットアップが必要になります。さらに、配列内の配列のサイズに関する情報が失われます(sizeofはポインターのサイズを示します)。一方、サブアレイのサイズを変更したり、ポインターが指す場所を変更したりする機能は、サイズ変更や再配置が必要な場合に便利です。このようなポインターの配列は、割り当ておよび配置が異なり、sizeofが常に同じように動作するわけではありませんが、多次元配列のようにインデックスを付けることができます。このセットアップの静的に割り当てられた例は次のとおりです。

int *arr[3];
int aa[2] = { 10, 11 }, 
    ab[2] = { 12, 13 }, 
    ac[2] = { 14, 15 };
arr[0] = aa;
arr[1] = ab;
arr[2] = ac;

上記の後、arr[1][0]12です。ただし、配列intの開始アドレスの1 * 2 * sizeof(int)バイトにあるarrを与える代わりに、arr[1]が指すアドレスの0 * sizeof(int)バイトにあるintを与えます。また、sizeof(arr[0])sizeof(int *)ではなくsizeof(int) * 2と同等です。

10
Dmitri

Cでは、多次元配列を理解するために知っておくべき特別なことは何もありません。それらは、特に言及されていないかのように機能します。知っておく必要があるのは、配列を含む任意のタイプの配列を作成できることです。

だからあなたが見るとき:

int matrix [2] [4];

matrixは2つの要素の配列です。これらの要素は4つの整数の配列です」と考えてください。配列のすべての通常の規則が適用されます。たとえば、matrixは、他の配列(この場合は4つの整数の配列)と同様に、最初のメンバーへのポインターに簡単に減衰できます。 (もちろん、それ自体が崩壊する可能性があります。)

2
David Schwartz

そのデータ(少量)にスタックを使用できる場合、通常、マトリックスを定義します。

int matrix[X][Y]

ヒープ(大容量)に割り当てる場合、通常は以下を定義します。

int** matrix = NULL;

次に、malloc/callocを使用して2つのディメンションを割り当てます。 2d配列はint **として扱うことができますが、コードが読みにくくなるため、これは良い習慣ではありません。それ以外

**matrix == matrix[0][0] is true
0
long404