我正在使用一个非常大的5D数组,我需要读入连续的内存(另一个5D数组)。我不能将数组放在堆栈上,因为它太大并且会产生seg错误。我所做的是用malloc动态创建一个5D数组,但是我发现它不是连续的内存。是否有一个优雅的解决方案,或者无论如何都会变得混乱?
答案 0 :(得分:4)
来自Jens Gustedt:Don't use fake matrices。
分配尺寸为A x B x C x D x E的五维矩阵(在编译时不需要知道尺寸),如下所示:
float (*matrix5d)[B][C][D][E] = malloc(sizeof(float[A][B][C][D][E]));
只需一次免费电话即可释放内存。
free(matrix5d);
请注意,对于可变长度数组,上述要求C99或更高。
答案 1 :(得分:2)
通过连续的内存块表示是C阵列的一个显着特性。多维数组是数组的数组,因此与任何其他数组的连续相同,所以如果你想要一个真正的5D数组,那么你肯定需要连续的内存。正如其他一些答案所观察到的那样,为了确保您获得连续的内存块,您必须立即分配整个内容。
虽然你可以构成数据结构,这些数据结构包含指向[[指向[...指针数组]指针数组的指针数组),这些指针根本不是同一个东西,就像指针不是数组一样。您可以使用索引运算符[]
和这样的数据结构,就像使用多维数组一样,但这并不能使它们成为同一个东西。
@EvelynParenteau建议使用1D阵列模拟您的5D阵列,这确实是满足您的邻接要求的一种方法。您甚至可以编写宏来更容易地将索引编入此类数组。
但只要您使用至少C99,就可以动态分配真正的5D阵列。一般形式可能如下所示:
void allocate_5d(unsigned dim1, unsigned dim2, unsigned dim3, unsigned dim4,
unsigned dim5, double (**aptr)[dim2][dim3][dim4][dim5]) {
*aptr = malloc(dim1 * sizeof(**aptr));
}
它会像这样使用:
void do_something(unsigned dim1, unsigned dim2, unsigned dim3, unsigned dim4,
unsigned dim5) {
double (*array)[dim2][dim3][dim4][dim5];
allocate_5d(dim1, dim2, dim4, dim4, dim5, &array);
if (!array) {
// Handle allocation failure ...
}
array[0][0][0][0][0] = 42;
// ...
free(array);
}
如果维度2 - 5是编译时常量,那么你甚至可以在C90中做这个(略有不同),但上面提到的变化取决于可变长度数组,这是C99中的新数据。
答案 2 :(得分:1)
考虑它的一种方法是使用malloc
来分配1d数组的4d数组,因为从根本上malloc
只能分配1d数组,而Nd数组只是1d数组(N -1)-d数组。
但是,就像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));
仍应有效,并允许您在每个维度上指定动态尺寸。
答案 3 :(得分:1)
有一种方法可以使记忆连续,但是它的优雅或凌乱是否会留给你;)
首先,让我们考虑一维数组的情况。在这种情况下,获得连续记忆是微不足道的;你从malloc
获得的记忆将是连续的。这似乎很简单,但我们以后会使用这个事实来获得一个5维连续数组。
现在,让我们考虑一个大小为M
N
的二维数组。这是创建一个方法的一种方式(假设我们正在使用float
)。
float** array2d = malloc(M * sizeof(float*));
for (int i = 0; i < M; i++) {
array2d[i] = malloc(N * sizeof(float));
}
严格来说,这是不是二维数组,它是一个数组数组。现在,我们可以访问array2d
的元素,例如array2d[0][0]
,array2d[0][1]
等。从概念上讲,这非常好,但正如您已经注意到的那样,我们不一定有连续性内存,因为我们对malloc
进行了多次调用。我们需要的是一种在M*N
的一次调用中分配存储malloc
浮点数所需的所有内存的方法。
float* array2d = malloc(M * N * sizeof(float));
请注意,在此表单中,array2d
是float*
而不是float**
,即它是一个浮点数组,而不是一个浮点数组数组。所以,我们不能再array2d[0][0]
了。我们现在如何索引这个数组?
完全取决于我们决定如何在内存中布置这个二维数组。让我们说M
是&#34;宽度&#34;数组(表示行中元素的数量)和N
是&#34; height&#34;数组(表示数组中的行数)。另外,我们只是说数组中的第一个M
条目是第一行,下一个M
条目是第二行,等等。所以要读取行{{ 1}},列y
,我们会这样做:
x
假设我们想要元素(0,0)。那么float data = array2d[y * M + x];
只会变为0,所以我们很好。现在说我们想要元素(1,0)(即第二行中的第一个元素)。然后,y * M + x
变为y * M + x
,我们上面已经确定了第二行的开始位置。
我们可以将这种方法推广到更高的维度。我们假设我们的M
大小为L
三维数组M
。您可以将此视为N
在内存中按顺序排列的二维数组,大小为L
M
。然后,要访问元素(N
,x
,y
),我们会这样做:
z
从概念上讲,您可以将此视为跳过第一个float data = array3d[z * (M * N) + y * (M) + x];
二维数组,然后跳过该数组的第一个z
行,然后转到该数组的y
元素行。对于更多维度,索引时有更多乘法项,但方法基本相同。
答案 4 :(得分:-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数组
答案 5 :(得分:-1)
如果我理解你的问题,你有一个当前的5D阵列,你需要为该阵列分配存储,并制作该阵列的副本,然后你希望以顺序的方式访问这些值。正如其他人所指出的那样,方法是使用指向4D数组的指针来分配一块内存dim1 * sizeof 4D
来保存现有的数组。 (您可以考虑分配 dim1行构成您的5D阵列的内容)。然后,您可以简单地复制现有数组(使用memcpy
等),然后指定第一个元素的指针以进行顺序访问。
好处是您可以分配一个块来保存现有阵列的副本。当您完成使用副本时,这只需要一个free
。
这不适用于假(指向指针的指针...... 内存集合)
以下是创建dim1
指针的简短示例,该指针指示现有数组的剩余4d(在单个块分配中)的内容,其中除了dim1
维之外的所有维度在编译时都是已知的。现有的5D阵列a
被复制到分配给b
的新内存块。然后为整数指针'p'分配b
的起始地址。 b
的值通过指针p
按顺序访问。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
int a[2][2][2][2][2] = { { { {{1,2}, {3,4}}, /* 5D Array */
{{5,6}, {7,8}} },
{ {{1,2}, {3,4}},
{{5,6}, {7,8}} } },
{ { {{1,2}, {3,4}},
{{5,6}, {7,8}} },
{ {{1,2}, {3,4}},
{{5,6}, {7,8}} } } };
/* ptr to 5D, ptr to int* */
int (*b)[2][2][2][2] = NULL, *p = NULL;
/* allocate block to hold a */
b = malloc (sizeof a/sizeof *a * sizeof *b);
memcpy (b, a, sizeof a/sizeof *a * sizeof *b); /* copy a to b */
p = ****b; /* assign address of first element */
printf ("\nb:\n"); /* ouput using sequential access */
for (int i = 0; i < (int)(sizeof a/sizeof *****a); i++)
printf (" *(p + %2d) : %d\n", i, p[i]);
free (b); /* single free is all that is required */
return 0;
}
示例使用/输出
$ ./bin/arr5dstatic1
b:
*(p + 0) : 1
*(p + 1) : 2
*(p + 2) : 3
*(p + 3) : 4
*(p + 4) : 5
*(p + 5) : 6
*(p + 6) : 7
*(p + 7) : 8
*(p + 8) : 1
*(p + 9) : 2
*(p + 10) : 3
*(p + 11) : 4
*(p + 12) : 5
*(p + 13) : 6
*(p + 14) : 7
*(p + 15) : 8
*(p + 16) : 1
*(p + 17) : 2
*(p + 18) : 3
*(p + 19) : 4
*(p + 20) : 5
*(p + 21) : 6
*(p + 22) : 7
*(p + 23) : 8
*(p + 24) : 1
*(p + 25) : 2
*(p + 26) : 3
*(p + 27) : 4
*(p + 28) : 5
*(p + 29) : 6
*(p + 30) : 7
*(p + 31) : 8
有充分的理由说明其余的评论和答案建议您找到除了使用5D阵列设置之外的其他方法。值得一提的是,您是否可以修改生成您在原始5D阵列中捕获的数据的任何内容,以便以其他格式输出数据。