0

連続したメモリ (別の 5D 配列) に読み込む必要がある非常に大きな 5D 配列を使用しています。配列が大きすぎてセグ フォールトが発生するため、配列をスタックに配置できません。私が行ったことは、malloc を使用して 5D 配列を動的に作成することですが、連続したメモリではないことがわかりました。これに対するエレガントな解決策はありますか、それとも面倒なことになるのでしょうか?

4

6 に答える 6

4

Jens Gustedt から:偽の行列を使用しないでください

次のように、次元 A x B x C x D x E (次元はコンパイル時に既知である必要はありません) を持つ 5 次元行列を割り当てます。

float (*matrix5d)[B][C][D][E] = malloc(sizeof(float[A][B][C][D][E]));

free を 1 回呼び出すだけでメモリを解放します。

free(matrix5d);

上記では、可変長配列には C99 以降が必要であることに注意してください。

于 2016-09-02T22:23:47.413 に答える
1

これについて考える 1 つの方法は、基本的に 1 次元配列のみを割り当てることができ、N 次元配列は (N-1) 次元配列の 1 次元malloc配列であるため、4 次元配列の 1 次元配列を割り当てるために使用することです。malloc

ただし、 によって割り当てられる配列と同様mallocに、「配列オブジェクト」は実際にはポインターであるため、 を使用sizeof()して配列のサイズを取得しないでください。

#include <stdio.h>
#include <stdlib.h>
typedef int Array_4D_Type[4][3][2][1];
int main(void) {
    Array_4D_Type *arr = malloc(5 * sizeof(Array_4D_Type));
   // ^^^^^^^^^^^^^^^^ here, allocate a length-5 vector of 4d array type
    int *p = &arr[0][0][0][0][0];
    for (int i = 0 ; i < 120 ; i++){
        p[i] = i;
    }
    printf("arr_start = %d, end = %d\n", arr[0][0][0][0][0], arr[4][3][2][1][0]);

    return 0;
}

ここでコードをテストできます

アップデート:

コメントに記載されているように、typedefここで使用すると、配列は最上位の次元を除いて静的なサイズになります。

ここでの使用は、typedef配列へのポインタの構文を少しきれいにするためだけです。

ただし、VLA が有効になってint (*arr)[n][o][p][q] = malloc(m*sizeof(*arr));いる場合でも機能し、各ディメンションで動的サイズを指定できます。

于 2016-09-02T18:45:33.023 に答える
1

メモリを連続させる方法はありますが、エレガントか乱雑かはあなた次第です ;)

まず、1 次元配列の場合を考えてみましょう。この場合、連続したメモリを取得するのは簡単です。取得するメモリはmalloc連続します。単純に思えますが、後でこの事実を使用して 5 次元の連続配列を取得します。

M次に、サイズがbyの 2 次元配列を考えてみましょうN。これを作成する 1 つの方法を次に示します ( floats を使用していると仮定します)。

float** array2d = malloc(M * sizeof(float*));
for (int i = 0; i < M; i++) {
  array2d[i] = malloc(N * sizeof(float));
}

厳密に言えば、これは2 次元配列ではなく、配列の配列です。これで、array2dlikeなどの要素にアクセスできます。概念的にはこれは非常に優れていますが、お気づきのように、 を複数回呼び出したので、必ずしも連続したメモリがあるとは限りません。必要なのは、float を格納するために必要なすべてのメモリを 1 回の呼び出しで割り当てる方法です。array2d[0][0]array2d[0][1]mallocM*Nmalloc

float* array2d = malloc(M * N * sizeof(float));

この形式でarray2dは、 はfloat*ではなくfloat**、つまり、float の配列の配列ではなく、float の配列であることに注意してください。ですから、これ以上はできませんarray2d[0][0]。この配列にどのようにインデックスを付けますか?

この 2 次元配列をメモリ内でどのようにレイアウトするかは、完全に私たち次第です。Mそれが配列の「幅」(行の要素数を意味する)であり、それNが配列の「高さ」(配列の行数を意味する)であるとしましょう。Mまた、配列の最初のエントリが最初の行であり、次のエントリが 2 番目の行であるとだけ言っておきましょうM。したがって、行y、列のエントリを読み取るには、次のxようにします。

float data = array2d[y * M + x];

要素 (0, 0) が必要だとします。その後y * M + x、単に 0 になるので、問題ありません。ここで、要素 (1, 0) (つまり、2 行目の最初の要素) が必要だとします。上で決定したように、これy * M + xM2 番目の行の開始点になります。

このアプローチを高次元に一般化できます。サイズLが byの 3 次元配列があるとMNます。これは、すべてのサイズがLのメモリ内に順番に配置された 2 次元配列と考えることができます。次に、要素 ( 、、) にアクセスするには、次のようにします。MNxyz

float data = array3d[z * (M * N) + y * (M) + x];

z概念的には、これは最初の2 次元配列をスキップし、次にyその配列の最初の行をスキップして、xその行の th 要素に移動すると考えることができます。次元が増えると、索引付け時に乗法項が増えますが、アプローチは基本的に同じです。

于 2016-09-02T18:53:38.430 に答える
-1

動的割り当てでは、malloc を使用します。

int** x;

x = malloc(dimension1_max * sizeof(int*));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = malloc(dimension2_max * sizeof(int));
}

[...]

for (int i = 0; i < dimension1_max; i++) {
  free(x[i]);
}
free(x);

これにより、サイズが dimension1_max * dimension2_max の 2D 配列が割り当てられます。したがって、たとえば、640*480 配列 (イメージの fe ピクセル) が必要な場合は、dimension1_max = 640、dimension2_max = 480 を使用します。その後、x[d1]​​[d2] (d1 = 0) を使用して配列にアクセスできます。 639、d2 = 0..479。

ただし、SOまたはGoogleで検索すると、他の可能性も明らかになります。たとえば、このSOの質問

その場合、配列はメモリの連続した領域 (640*480 バイト) を割り当てないことに注意してください。これを前提とする関数で問題が発生する可能性があります。したがって、条件を満たす配列を取得するには、上記の malloc ブロックを次のように置き換えます。

int** x;
int* temp;

x = malloc(dimension1_max * sizeof(int*));
temp = malloc(dimension1_max * dimension2_max * sizeof(int));
for (int i = 0; i < dimension1_max; i++) {
  x[i] = temp + (i * dimension2_max);
}

[...]

free(temp);
free(x);

同様の方法で、動的に 5d 配列を構築できます

于 2016-09-02T18:42:16.473 に答える