我正在处理可变大小的3D和4D阵列,它们必须是连续的(有时比common
'方式更容易调用*(&x[0][0][0] + k)
。 '因为数组的大小可变,我需要动态分配。我发现这个代码,在另一个答案(Dynamic memory allocation for 3D array)中做到这一点,它工作正常,但我不知道堆栈的内存使用量。
x[][][]
问题是:
double ***arr3dAlloc(const int ind1, const int ind2, const int ind3) {
int i;
int j;
double ***array = (double***)malloc((ind1 * sizeof(double*)) +
(ind1 * ind2 * sizeof(double**)) +
(ind1 * ind2 * ind3 * sizeof(double)));
for (i = 0; i < ind1; ++i) {
array[i] = (double**)(array + ind1) + i * ind2;
for (j = 0; j < ind2; ++j) {
array[i][j] = (double*)(array + ind1 + ind1 * ind2) + i * ind2 * ind3 + j * ind3;
}
}
return array;
}
和double ***arr1 = arr3dAlloc(N1,N2,N3);
之间有什么区别
鉴于double arr2[N1][N2][N3];
使用了堆栈的arr2
内存,N1*N2*N3*sizeof(double)
使用了多少内存?只有arr1
?
答案 0 :(得分:1)
指针具有指针的大小,具有相应的机器体系结构
(现在经常是long
或long long
)。该大小与所引用的内存类型无关。 (“**
”只是指另一个指针。)
数组类型[N] 始终分配 sizeof(type)* N 字节的内存。 sizeof()
包括类型填充到正确的对齐边界。
因此,使用malloc(sizof(type)*N)
将为 type 的 N 元素数组分配足够的内存,从而提供指向已分配内存块的指针。您也可以使用calloc()
将内存初始化为零。
由于分配的内存不依赖于多维数组的组织,因此这种方法适用于任意数量的维度&gt; = 1.
解决您的问题:
double ***arr1 = …
只是将指针存储到某个内存区域,
而arr2[N1][N2][N3]
正在为N1*N2*N3
双打分配填充空间。arr1
使用sizeof(void *)
个字节,
而arr2
正在使用N1*N2*n3*sizeof(double)
字节。sizeof(var)
总是给出变量的大小,
这是在数据/ bss段还是在堆栈上。答案 1 :(得分:1)
您的代码分配一个3D数组和指向double
指针数组的指针数组,以通过双重间接访问其元素。这种方法存在一些问题:
您的代码未在double
边界上对齐double
数组。如果指针的大小为4个字节且数组的大小为3x4x5,则double
数组将不对齐,这可能会在某些系统上导致未定义的行为。
您的尺寸计算中使用的类型是近似值。
int
可能会溢出。这是一个更正版本(假设所有指针类型具有相同的大小):
double ***arr3dAlloc(int ind1, int ind2, int ind3) {
size_t level1_size = sizeof(double**) * ind1;
size_t level2_size = sizeof(double*) * ind1 * ind2;
size_t padding = (sizeof(double) - (level1_size + level2_size) % sizeof(double))
% sizeof(double);
size_t level3_size = sizeof(double) * ind1 * ind2 * ind3;
int i, j;
double ***array = calloc(1, level1_size + level2_size + padding + level3_size);
double *array3d = (double*)((unsigned char*)array + level1_size + level2_size + padding);
for (i = 0; i < ind1; ++i) {
array[i] = (double**)(array + ind1) + i * ind2;
for (j = 0; j < ind2; ++j) {
array[i][j] = array3d;
array3d += ind3;
}
}
return array;
}
请注意,使用C99,您可以分配可直接在主计算代码中使用的真实3D数组:
/* array3d is a pointer to an allocated 3D array: */
double (*array3d)[ind2][ind3] = calloc(sizeof(*array3d), ind1);
/* array3d can be used like a statically defined array: */
for (int i = 0; i < ind1; i++) {
for (int j = 0; j < ind2; j++) {
for (int k = 0; k < ind3; k++) {
array3d[i][j][k] = i + j + k;
}
}
}
答案 2 :(得分:0)
这里有几个问题需要解决。
第一个是全局变量,堆和堆栈之间的区别。这些都是RAM的所有部分。 malloc()分配一部分堆并返回一个指针。这在互联网上的许多其他地方都有讨论。
另一个问题是编译时与运行时分配。对于编译时分配,必须事先知道数组的大小。您的示例使用运行时分配(malloc()
),因为数组的大小作为变量传递给函数。在编译时不知道它的大小,就无法在堆栈或全局变量中分配数组。