Malloc是C中的三维数组?

我正在将一些MATLAB代码翻译成C,我正在转换的脚本大量使用具有10 * 100 * 300复杂条目的3D数组。 数组的大小也取决于传感器的输入,理想情况下应该动态分配数组。 到目前为止,我已经尝试了两种方法,第一种方法是平面1Darrays

value = array[x + (y*xSize) + (z*ySize*xSize)] 

这伤害了我的大脑使用。 我还尝试了一个指针数组的数组

 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; } 

当我尝试分配数据时,会出现seg错误。

在一个完美的世界中,我想使用数组符号的第二种方法来实现更清晰,更简单的编程。 有没有更好的方法在C中动态分配三维数组?

我会选择第一个选项(单个1Darrays),因为它会为你提供一个单独的内存块,而不是潜在的数千个碎片内存块

如果访问数组的正确元素正在努力,我会写一个实用工具方法将x,y,z位置转换为1D数组的偏移量

 int offset(int x, int y, int z) { return (z * xSize * ySize) + (y * xSize) + x; } 

正如其他人所说,最好分配一个连续的内存块,然后自己弄清楚索引。 如果需要,您可以编写一个函数来执行此操作。 但是既然您似乎对如何处理多个malloc()情况感兴趣,这里有一个例子:

首先,我定义了一个函数free_data() ,它释放了一个以xlenylen作为前两个维度大小的int *** 。 我们不需要一个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); } 

该函数循环遍历指针data ,找出第iint **指针data[i] 。 然后,对于给定的int **指针,它遍历它,在data[i][j]找出j th int * ,并释放它。 它还需要在释放所有data[i][j]释放data[i][j] ,最后,它需要释放data本身。

现在来分配function。 错误检查function有点复杂。 特别是,由于有1 + xlen + xlen*ylen malloc调用,我们必须能够处理任何这些调用中的失败,并释放到目前为止我们分配的所有内存。 为了简化操作,我们依赖于free(NULL)是无操作的事实,所以在我们尝试分配它们之前,我们将给定级别的所有指针设置为NULL ,这样如果发生错误,我们可以释放所有的指针。

除此之外,function很简单。 我们首先为xlen int **值分配空间,然后对于每个xlen指针,我们为ylen int *值分配空间,然后对于每个xlen*ylen指针,我们为zlen int值分配空间,给我们一个xlen*ylen*zlen int值的总空间:

 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; } 

请注意,我已经简化了malloc调用:通常,您不应该转换malloc的返回值,并将您要分配的对象指定为sizeof运算符的操作数而不是其类型。 这使得malloc调用更容易编写,并且不易出错。 您需要为malloc包含stdlib.h

这是一个使用上述两个函数的测试程序:

 #include  #include  #include  #include  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; } 

如果您发现它更容易使用,请务必使用此方法。 一般来说,这比使用连续的大块内存要慢,但是如果你发现上述方案的速度没问题,并且如果它让你的生活更轻松,你可以继续使用它。 即使你不使用它,也很高兴知道如何使这样的方案工作。

你确定需要使用malloc吗? C允许本地创建多维数组:

 int a2[57][13][7]; 

或者您可以通过以下方式使用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 

C89中没有办法做你想做的事情,因为C中的数组类型只能用编译时已知值指定。 因此,为了避免疯狂的动态分配,你必须坚持一维方式。 您可以使用一个function来简化此过程

 int index(int x, int y, int z) { return x + (y*xSize) + (z*ySize*xSize); } int value = array[index(a, b, c)]; 

在C99中,即使维度是运行时值,也可以使用普通的数组语法:

 int (*array)[X][Y][Z] = (int(*)[X][Y][Z])malloc(sizeof *p); // fill... int value = (*array)[a][b][c]; 

但是,它仅适用于本地非静态数组。

哦,我讨厌malloc数组分配^^

这是一个正确的版本,基本上它只是一个不正确的行:

 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; } 

通过这种方式,您只能分配1个内存块,动态数组的行为类似于静态内存(即相同的内存连续性)。 您还可以使用像普通1-Darrays一样的单个空闲(数组)释放内存。

 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; } 

关于segfault,我很确定其他人已经指出了这个,但为了以防万一,在第一个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)); } } 

尝试以下方法:

  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)); } } 

希望对你有帮助!!!!

在为3Darrays内部分配2Darrays的内存时,将分配的内存分配给array [i]而不是* array [i],这将在没有seg错误的情况下工作。

这是你的计划

 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; 

}

您迫使自己将这视为分配3Darrays的两种根本不同的方式。 这种看法通过两个明确的区分细节得到加强:1)第二种方法使用几个间接级别来访问实际元素,2)第二种方法独立地分配低级别1Darrays。

但是你为什么要坚持分别分配低级别的1Darrays呢? 你不必那样做。 一旦你考虑到它,你应该意识到有第三种方法来构建你的3Darrays

 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; 

如果你仔细看一下这个分配方法,你应该看到最终这与你的第二个方法几乎是一样的:它通过在每个间接层使用中间指针来构建一个三级数组结构。 唯一的区别是它预先为每个间接级别预先分配内存,“一次性”,而不是进行多次重复的malloc调用。 后续循环只是在子数组中分配预先分配的内存(即它只是初始化指针)。

但是,如果你看得更近,你还会注意到实际的数组元素内存(存储实际值的int )的分配方式与第一种方法完全相同: malloc(3 * 3 * 3 * sizeof(int)); - 作为一个平坦的连续arrays。

现在,如果您考虑一下,您应该意识到第三种方法与您的第一种方法没有太大区别。 它们都使用大小为xSize * ySize * zSize的平面数组来存储数据。 这里唯一真正的区别是我们用来计算访问该平面数据的索引的方法。 在第一种方法中,我们将即时计算索引

 array1d[z * ySize * xSize + y * xSize + x] 

在第三种方法中,我们预先使用基本相同的公式预先计算指向数组元素的指针,将预先计算的结果存储在其他数组中,然后使用“自然”数组访问语法检索它们

 array3d[x][y][x] 

这里的问题是这个预计算是否值得额外的努力和额外的记忆。 答案是:一般不,不是。 通过花费这些额外的内存,您将无法获得任何可观的性能优势(很可能会使您的代码变慢)。

第二种方法可能值得考虑的唯一情况是当你处理真正的锯齿状/粗糙数组时:一个稀疏的多维数组,其中一些子数组部分缺失/未使用或者尺寸减小。 例如,如果已知3Darrays的某些1D或2D子arrays只包含零,则可能决定不将它们存储在内存中,并将相应的指针设置为null。 这意味着使用第二种方法,其中子arrays是独立分配(或不分配)的。 如果数据很大,那么节省的内存可能是值得的。

还要注意,当我们讨论具有3个或更多维度的数组时,可以同时使用第一个/第二个/第三个分配方法,同时用于不同级别的间接。 您可能决定使用第一种方法实现2D数组,然后使用第二种方法将它们组合成3D数组。

在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 

添加#include“stdlib.h”并删除* from * array [i],它将在Ubuntu上的gcc 4.4.1中编译时运行

此外,如果您添加打印语句,您可以更快地找到您的错误

 #include  #include  int main () { int ***array = malloc(3*sizeof(int**)); int i, j; printf("%s\n","OK"); for (i = 0; i < 3; i++) { printf("i = %i \n",i); array[i] = malloc(3*sizeof(int*)); for (j = 0; j < 3; j++) { printf("i,j = %i,%i \n",i,j); array[i][j] = malloc(3*sizeof(int)); } } array[1][2][1] = 10; return 0; } 
 #include #include #define MAXX 3 #define MAXY 4 #define MAXZ 5 main() { int ***p,i,j; p=(int ***) malloc(MAXX * sizeof(int **)); for(i=0;i < MAXX;i++) { p[i]=(int **)malloc(MAXY * sizeof(int *)); for(j=0;j < MAXY;j++) p[i][j]=(int *)malloc(MAXZ * sizeof(int)); } for(k=0;k < MAXZ;k++) for(i=0;i < MAXX;i++) for(j=0;j < MAXY;j++) p[i][j][k]= < something >; } 

这应该工作,你不是类型转换malloc的返回值

 #include  int main () { int ***array = (int ***) malloc(3*sizeof(int**)); int i, j; for (i = 0; i < 3; i++) { 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; printf("%d\n", array[1][2][1]); return 0; } 

工作链接: http : //ideone.com/X2mcb8