web-dev-qa-db-ja.com

2D配列と配列の配列

2D配列と配列の配列の違いは何ですか?

@ Dave's など、2つを区別しているように見えるコメントを読みました。

彼が配列の配列ではなく、2D配列、または配列へのポインター型を使用している場合、これは壊れます。 –デイブ

私はいつも両方が言及していると思っていました:

int arr_arr[][];

EDIT:@ FutureReader、あなたは見たいかもしれません C++で配列を使用するにはどうすればよいですか?

11
Mateen Ulhaq

2次元配列is定義上、配列の配列。

Daveが言っていたのは、そのコンテキストでは、2D配列の定義間に次のような異なるセマンティクスがあるということです。

int x[][];

この:

int *x[];

またはこれ:

int **x;
10
Jacob Relkin

ここには4つの異なる概念があります。

  • 2次元配列: _int arr[][]_。どの方向にもサイズ変更できず、連続しています。索引付けは_((int*)arr)[y*w + x]_と同じです。静的に割り当てる必要があります。
  • ポインタ-配列へ:int (*arr)[]。サイズを変更して行を追加することのみが可能で、連続しています。索引付けは_((int*)arr)[y*w + x]_と同じです。動的に割り当てる必要がありますが、解放できますfree(x);
  • ポインタからポインタへ: _int **arr_。サイズは任意の方向に変更でき、必ずしも正方形である必要はありません。通常は動的に割り当てられますが、必ずしも連続している必要はありません。解放はその構造に依存します。インデックス付けは*(*(arr+y)+x)と同じです。
  • ポインタの配列: _int *arr[]_。列を追加するためにのみサイズ変更でき、必ずしも正方形である必要はありません。サイズ変更と解放も構造によって異なります。インデックス付けは*(*(arr+y)+x)と同じです。

これらはすべて_arr[y][x]_を使用できるため、混乱を招きます。

26
Dave

ここでの答えはもう少し微妙です。

配列の配列は、次のように定義されています。

int array2[][];

配列へのポインタ型は次のように定義されます。

int (*array2)[];

ポインターの配列タイプは次のように定義されます。

int* array2[];

コンパイラーはこれらの両方を少し異なる方法で処理します。実際、もう1つのオプションがあります。

int** array2;

多くの人がこれら3つは同一であると教えられていますが、コンパイラについてもっと知っていれば、違いは小さいことが確かにわかりますが、それはそこにあります。あるプログラムを別のプログラムに置き換えると多くのプログラムが実行されますが、コンパイラーとASMレベルでは同じではありません。 Cコンパイラに関する教科書は、はるかに詳細な答えを提供するはずです。

また、2D配列の実装に関心がある場合は、状況に応じて効率が異なる複数の方法があります。 2D配列を1D配列にマップできます。これにより、線形化されたデータを処理するときに空間的な局所性が保証されます。プログラミングを簡単にしたい場合や、行/列を個別に操作する必要がある場合は、配列の配列を使用できます。キャッシュスマートな特定のブロックされたタイプやその他の凝ったデザインがありますが、ユーザーの場合、実装を知る必要はめったにありません。

私が助けてくれたらいいのに!

10
foslock

以下は、配列の配列と呼ばれる2D配列です。

_int AoA[10][10];
_

以下は、2D配列として機能するように設定されたポインターへのポインターです。

_int **P2P = malloc(10 * sizeof *P2P);
if(!P2P) exit(1);
for(size_t i = 0; i < 10; i++)
  {
    P2P[i] = malloc(10 * sizeof **P2P);
    if(!P2P[i])
      {
        for(; i > 0; i--)
            free(P2P[i - 1]);
        free(P2P); 
      }
  }
_

どちらも_AoA[x][y]_または_P2P[x][y]_からアクセスできますが、互換性はありません。特に、_P2P = AoA_は初心者が時々動作することを期待するものですが、動作しません-_P2P_はポインタを指すことを期待しますが、AoAがポインタに崩壊するとき、それはポインタです- 配列へ、具体的にはint (*)[10]、これは_int **_が想定している_P2P_ではありません。

1
Chris Lutz

2D配列には次のものを含めることができます。

int x[width * height]; // access: x[x + y * width];

ウィキペディアから:

2次元配列の場合、インデックスi、jを持つ要素はアドレスB + c・i + d・jを持ちます。ここで、係数cおよびdは、それぞれ行および列のアドレス増分です。

0
Pubby