C语言 在 C 中分配一个 3 维数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2306172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Malloc a 3-Dimensional array in C?
提问by Mike
I'm translating some MATLAB code into C and the script I'm converting makes heavy use of 3D arrays with 10*100*300 complex entries. The size of the array also depends on the sensor's input, ideally the array should be allocated dynamically. So far I've tried two approaches the first being a flat 1D array along the lines of
我正在将一些 MATLAB 代码翻译成 C,我正在转换的脚本大量使用了 10*100*300 复杂条目的 3D 数组。数组的大小还取决于传感器的输入,理想情况下应该动态分配数组。到目前为止,我已经尝试了两种方法,第一种是沿着
value = array[x + (y*xSize) + (z*ySize*xSize)]
Which hurts my brain to use. I've also tried an array of an array of pointers
这伤害了我的大脑使用。我也试过一个数组的指针数组
int main () {
int ***array = malloc(3*sizeof(int**));
int i, j;
for (i = 0; i < 3; i++) {
*array[i] = malloc(3*sizeof(int*));
for (j = 0; j < 3; j++) {
array[i][j] = malloc(3*sizeof(int));
}
}
array[1][2][1] = 10;
return 0;
}
Which gives a seg fault when I try to assign data.
当我尝试分配数据时,这会导致段错误。
In a perfect world, I'd like to use the second method with the array notation for cleaner, easier programming. Is there a better way to dynamically allocate a three-dimensional array in C?
在一个完美的世界中,我想将第二种方法与数组表示法一起使用,以实现更清晰、更轻松的编程。有没有更好的方法在 C 中动态分配一个三维数组?
回答by tim_yates
I'd go for the first option (the single 1D array) as it will give you a single block of memory to play in rather than potentially thousands of fragmented memory blocks
我会选择第一个选项(单个一维数组),因为它会给你一个内存块来播放,而不是潜在的数千个碎片内存块
If accessing the correct element of the array is doing your head in though, I'd write a utility method to convert x, y, z locations into an offset into the 1D array
如果访问数组的正确元素是你的头脑,我会写一个实用方法来将 x、y、z 位置转换为一维数组的偏移量
int offset(int x, int y, int z) {
return (z * xSize * ySize) + (y * xSize) + x;
}
回答by Alok Singhal
As others have said, it is probably better to allocate one contiguous chunk of memory, and then figure out the indexing yourself. You can write a function to do so if you want. But since you seem to be interested in knowing how to deal with the multiple malloc()case, here is an example:
正如其他人所说,最好分配一个连续的内存块,然后自己找出索引。如果需要,您可以编写一个函数来执行此操作。但由于您似乎对了解如何处理多个malloc()案例感兴趣,这里有一个例子:
First, I define a function free_data(), which frees an int ***with xlenand ylenas the first two dimension sizes. We don't need a zlenparameter just like free()doesn't take the length of the pointer being freed.
首先,我定义一个函数free_data(),从而释放一个int ***带xlen和ylen与第一二维尺寸。我们不需要zlen参数就像free()不需要被释放的指针的长度一样。
void free_data(int ***data, size_t xlen, size_t ylen)
{
size_t i, j;
for (i=0; i < xlen; ++i) {
if (data[i] != NULL) {
for (j=0; j < ylen; ++j)
free(data[i][j]);
free(data[i]);
}
}
free(data);
}
The function loops over the pointer data, finds out the ith int **pointer data[i]. Then, for a given int **pointer, it loops over it, finding out the jth int *in data[i][j], and frees it. It also needs to free data[i]once it has freed all data[i][j], and finally, it needs to free dataitself.
该函数遍历指针data,找出i第 th 个int **指针data[i]。然后,对于给定的int **指针,它循环遍历它,找出jth int *in data[i][j],并释放它。data[i]一旦它释放了所有data[i][j],它也需要释放,最后,它需要释放data自己。
Now to the allocation function. The function is a bit complicated by error checking. In particular, since there are 1 + xlen + xlen*ylenmalloccalls, we have to be able to handle a failure in any of those calls, and free all the memory we allocated so far. To make things easier, we rely on the fact that free(NULL)is no-op, so we set all the pointers at a given level equal to NULLbefore we try to allocate them, so that if an error happens, we can free all of the pointers.
现在到分配函数。该函数通过错误检查有点复杂。特别是,由于有1 + xlen + xlen*ylenmalloc调用,我们必须能够处理任何调用中的失败,并释放我们迄今为止分配的所有内存。为了使事情更容易,我们依赖于free(NULL)无操作这一事实,因此我们NULL在尝试分配它们之前将给定级别的所有指针设置为等于,这样如果发生错误,我们可以释放所有指针。
Other than that, the function is simple enough. We first allocate space for xlenint **values, then for each of those xlenpointers, we allocate space for ylenint *values, and then for each of those xlen*ylenpointers, we allocate space for zlenintvalues, giving us a total space for xlen*ylen*zlenintvalues:
除此之外,该功能很简单。我们首先为xlenint **值分配空间,然后为每个xlen指针分配空间ylenint *,然后为每个xlen*ylen指针分配空间zlenint,从而为值提供总空间xlen*ylen*zlenint:
int ***alloc_data(size_t xlen, size_t ylen, size_t zlen)
{
int ***p;
size_t i, j;
if ((p = malloc(xlen * sizeof *p)) == NULL) {
perror("malloc 1");
return NULL;
}
for (i=0; i < xlen; ++i)
p[i] = NULL;
for (i=0; i < xlen; ++i)
if ((p[i] = malloc(ylen * sizeof *p[i])) == NULL) {
perror("malloc 2");
free_data(p, xlen, ylen);
return NULL;
}
for (i=0; i < xlen; ++i)
for (j=0; j < ylen; ++j)
p[i][j] = NULL;
for (i=0; i < xlen; ++i)
for (j=0; j < ylen; ++j)
if ((p[i][j] = malloc(zlen * sizeof *p[i][j])) == NULL) {
perror("malloc 3");
free_data(p, xlen, ylen);
return NULL;
}
return p;
}
Note that I have simplified malloccalls quite a bit: in general, you shouldn't cast the return value of malloc, and specify the object you're allocating for as the operand to sizeofoperator instead of its type. That makes malloccalls simpler to write and less error-prone. You need to include stdlib.hfor malloc.
请注意,我对malloc调用进行了相当多的简化:通常,您不应强制转换 的返回值malloc,并将您要分配的对象指定为运算sizeof符的操作数,而不是其类型。这使得malloc调用更易于编写且不易出错。您需要包括stdlib.hfor malloc。
Here is a test program using the above two functions:
下面是一个使用上述两个函数的测试程序:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
int ***data;
size_t xlen = 10;
size_t ylen = 100;
size_t zlen = 300;
size_t i, j, k;
srand((unsigned int)time(NULL));
if ((data = alloc_data(xlen, ylen, zlen)) == NULL)
return EXIT_FAILURE;
for (i=0; i < xlen; ++i)
for (j=0; j < ylen; ++j)
for (k=0; k < zlen; ++k)
data[i][j][k] = rand();
printf("%d\n", data[1][2][1]);
free_data(data, xlen, ylen);
return EXIT_SUCCESS;
}
By all means use this approach if you find it easier to use it. In general, this will be slower than using a contiguous chunk of memory, but if you find that the speed is OK with the above scheme, and if it makes your life easier, you can keep using it. Even if you don't use it, it is nice to know how to make such a scheme work.
如果您发现它更易于使用,请务必使用此方法。一般来说,这会比使用连续的内存块慢,但是如果您发现上述方案的速度还可以,并且如果它使您的生活更轻松,则可以继续使用它。即使您不使用它,也很高兴知道如何使这样的方案起作用。
回答by Dims
Are you sure you need to use malloc? C allows creating of multidimentional arrays natively:
您确定需要使用malloc吗?C 允许本机创建多维数组:
int a2[57][13][7];
Or you can use mallocin the following way:
或者您可以通过malloc以下方式使用:
int (*a)[13][7]; // imitates 3d array with unset 3rd dimension
// actually it is a pointer to 2d arrays
a = malloc(57 * sizeof *a); // allocates 57 rows
a[35][7][3] = 12; // accessing element is conventional
free(a); // freeing memory
回答by Johannes Schaub - litb
There is no way in C89 to do what you desire, because an array type in C can only be specified with compile time known values. So in order to avoid the mad dynamic allocation, you will have to stick to the one dimensional way. You may use a function to ease this process
在 C89 中没有办法做你想做的事,因为 C 中的数组类型只能用编译时已知的值来指定。所以为了避免疯狂的动态分配,你将不得不坚持一维方式。你可以使用一个函数来简化这个过程
int index(int x, int y, int z) {
return x + (y*xSize) + (z*ySize*xSize);
}
int value = array[index(a, b, c)];
In C99 you can use an ordinary array syntax even if the dimensions are runtime values:
在 C99 中,即使维度是运行时值,您也可以使用普通数组语法:
int (*array)[X][Y][Z] = (int(*)[X][Y][Z])malloc(sizeof *p);
// fill...
int value = (*array)[a][b][c];
However, it only works with local non-static arrays.
但是,它仅适用于本地非静态数组。
回答by AndiDog
Oh do I hate malloc array allocation ^^
哦,我讨厌 malloc 数组分配 ^^
Here's a correct version, basically it was just one incorrect line:
这是一个正确的版本,基本上它只是一个错误的行:
int main () {
int ***array = (int***)malloc(3*sizeof(int**));
int i, j;
for (i = 0; i < 3; i++) {
// Assign to array[i], not *array[i] (that would dereference an uninitialized pointer)
array[i] = (int**)malloc(3*sizeof(int*));
for (j = 0; j < 3; j++) {
array[i][j] = (int*)malloc(3*sizeof(int));
}
}
array[1][2][1] = 10;
return 0;
}
回答by Alberto
In this way you can allocate only just 1 block of memory and the dynamic array behaves like the static one (i.e. same memory contiguity). You can also free memory with a single free(array) like ordinary 1-D arrays.
通过这种方式,您只能分配 1 个内存块,并且动态数组的行为类似于静态数组(即相同的内存连续性)。您还可以像普通一维数组一样使用单个 free(array) 释放内存。
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;
}
回答by Quref
Hope this will help you!!!!
希望能帮到你!!!!
While allocating memory for 2D array inside 3D array, assign the allocated memory to array[i] and not *array[i] and this will work without seg fault.
在为 3D 数组中的 2D 数组分配内存时,将分配的内存分配给 array[i] 而不是 *array[i],这将在没有段错误的情况下工作。
Here is your program
这是你的程序
int main ()
{
int ***array = malloc(3*sizeof(int**));
int i, j;
for (i = 0; i < 3; i++) {
array[i] = malloc(3*sizeof(int*));
for (j = 0; j < 3; j++) {
array[i][j] = malloc(3*sizeof(int));
}
}
array[1][2][1] = 10;
return 0;
}
回答by Malcolm McCullough
About the segfault, I am pretty sure someone else has pointed this out but just in case, there is a extra '*' in the first line of the first for loop
关于段错误,我很确定其他人已经指出了这一点,但以防万一,第一个 for 循环的第一行中有一个额外的“*”
for (i = 0; i < 3; i++) {
*array[i] = malloc(3*sizeof(int*));
// ^ we dont want to deference array twice
for (j = 0; j < 3; j++) {
array[i][j] = malloc(3*sizeof(int));
}
}
try the following:
尝试以下操作:
for (i = 0; i < 3; i++) {
array[i] = malloc(3*sizeof(int*));
for (j = 0; j < 3; j++) {
array[i][j] = malloc(3*sizeof(int));
}
}
回答by ashutosh
Below the Code for 3d memory allocations:
在 3d 内存分配代码下方:
int row3d = 4;
int column3d = 4;
int height3d =4;
int val3d =10;
int ***arr3d = (int***)malloc (row3d*sizeof(int**));
for (int i =0 ; i<column3d;i++)
{
arr3d[i] = (int**)malloc (column3d*sizeof(int*));
for (int j = 0;j<height3d;j++)
{
arr3d[i][j] = (int*)malloc (height3d*sizeof(int));
for (int z =0;z<height3d;z++,val3d++)
{
arr3d[i][j][z] = val3d;
}
}
}
// De allocation.
for (int i=0;i<row3d;i++)
{
for(int j=0;j<column3d;j++)
{
free(arr3d[i][j]);
}
}
free(arr3d);
arr3d = 0;
回答by AnT
You are forcing yourself into perceiving this as two fundamentally different ways to allocate a 3D array. This perception is reinforced by twodefinitive differentiating details: 1) the second method uses several levels of indirectionto access the actual elements, 2) the second method allocates the lower-level 1D arrays independently.
您正在强迫自己将其视为分配 3D 数组的两种根本不同的方式。两个明确的区分细节加强了这种看法:1) 第二种方法使用多个间接级别来访问实际元素,2) 第二种方法独立分配较低级别的 1D 数组。
But why exactly do you insist on allocating the lower-level 1D arrays independently? You don't have to do that. And once you take it into account, you should realize that there's a third method of building your 3D array
但是为什么你坚持独立分配较低级别的一维数组?你不必那样做。一旦你把它考虑在内,你应该意识到还有第三种构建 3D 阵列的方法
int ***array3d = malloc(3 * sizeof(int **));
int **array2d = malloc(3 * 3 * sizeof(int *));
int *array1d = malloc(3 * 3 * 3 * sizeof(int));
for (size_t i = 0; i < 3; i++)
{
array3d[i] = array2d + i * 3;
for (size_t j = 0; j < 3; j++)
array3d[i][j] = array1d + i * 3 * 3 + j * 3;
}
array[1][2][1] = 10;
If you look at this allocation method closely, you should see that in the end this is pretty much the same thing as your second method: it builds a three-level array structure by using intermediate pointers at each level of indirection. The only difference is that it pre-allocates memory for each level of indirection contiguously, "in one shot", beforehand, instead of making multiple repetitive malloccalls. The subsequent cycle simply distributes that pre-allocated memory among the sub-arrays (i.e. it simply initializes the pointers).
如果你仔细观察这个分配方法,你应该看到最后这和你的第二种方法几乎一样:它通过在每个间接级别使用中间指针来构建一个三级数组结构。唯一的区别是它预先为每个间接级别连续预分配内存,“一次性”,而不是进行多次重复malloc调用。随后的循环简单地在子数组之间分配预先分配的内存(即它简单地初始化指针)。
However, if you look even closer, you'll also notice that the actual array element memory (the ints that store actual the values) are allocated in exactly the same way as they would be in your first method: malloc(3 * 3 * 3 * sizeof(int));- as a plain flat contiguous array.
但是,如果您仔细观察,您还会注意到实际的数组元素内存(int存储实际值的s)的分配方式与您在第一种方法中的分配方式完全相同:malloc(3 * 3 * 3 * sizeof(int));- 作为一个普通的平面连续大批。
Now, if you think about it, you should realize that this third method is not much different from your first. They both use a flat array of size xSize * ySize * zSizeto store the data. The only real difference here is the method we use to calculate the index to access that flat data. In the first method we'd calculate the index on-the-fly as
现在,如果您考虑一下,您应该意识到这第三种方法与您的第一种方法没有太大区别。它们都使用大小xSize * ySize * zSize为平面的数组来存储数据。这里唯一真正的区别是我们用来计算索引以访问平面数据的方法。在第一种方法中,我们将即时计算索引为
array1d[z * ySize * xSize + y * xSize + x]
in the third method we pre-calculate the pointers to array elements in advance, using essentially the same formula, store the pre-calculated results in additional arrays and retrieve them later using the "natural" array access syntax
在第三方法中,我们预先计算指针数组元素提前,使用基本上相同的公式,存储在附加阵列中的预先计算的结果和以后使用的“自然”排列访问语法检索它们
array3d[x][y][x]
The question here is whether this pre-calculation is worth the extra effort and extra memory. The answer is: generally no, it is not. By spending this extra memory you will not reap any appreciable performance benefits (chances are it will make your code slower).
这里的问题是这种预先计算是否值得付出额外的努力和额外的内存。答案是:一般不会,不是。通过使用这些额外的内存,您不会获得任何明显的性能优势(它可能会使您的代码变慢)。
The only situation where your second method might be worth considering is when you are dealing with genuinely jagged/raggedarray: a sparse multi-dimensional array with some sub-arrays parts missing/unused or having reduced size. For example, if some 1D or 2D sub-arrays of your 3D array are known to contain just zeros, you might decide not to store them in memory at all and set the corresponding pointers to null. This would imply using your second method, where the sub-arrays are allocated (or not allocated) independently. If the data is large the resultant memory savings could be well worth it.
您的第二种方法可能值得考虑的唯一情况是当您处理真正锯齿状/参差不齐的数组时:稀疏的多维数组,其中一些子数组部分丢失/未使用或大小减小。例如,如果已知 3D 数组的某些 1D 或 2D 子数组仅包含零,您可能决定根本不将它们存储在内存中并将相应的指针设置为 null。这意味着使用您的第二种方法,其中子数组是独立分配(或不分配)的。如果数据很大,那么节省的内存可能是值得的。
Also note that when we are talking about arrays with 3 and more dimensions, the first/second/third allocation methods can be used together, simultaneously for different levels of indirection. You might decide to implement 2D arrays using the first method and then combine them into a 3D array using the second method.
另请注意,当我们讨论具有 3 维或更多维的数组时,可以同时使用第一/第二/第三分配方法,同时用于不同级别的间接。您可能决定使用第一种方法实现 2D 数组,然后使用第二种方法将它们组合成 3D 数组。

