使用malloc作为结构的多维数组

这可能是一个基本问题,但我想为结构的三维数组分配内存。 我正在尝试从文件中读取双打并想要存储在struct中。 第一行是块编号(这里不相关,因为它总是1),第二行分别表示X,Y和Z坐标中的网格点数。 在这种情况下,X中有10个点,Y中有5个,Z方向上有1个。 从第三行开始,每个点的X,Y,Z坐标是我想要阅读的双打。 首先是所有X分量(即10 * 5 * 1 x坐标,然后类似Y和Z)。 文件格式如下:

1 10 5 1 0.000000e+00 1.111111e+00 2.222222e+00 3.333333e+00 4.444445e+00 5.555555e+00 6.666667e+00 7.777778e+00 8.888889e+00 1.000000e+01 0.000000e+00 1.111111e+00 2.222222e+00 3.333333e+00 4.444445e+00 5.555555e+00 6.666667e+00 7.777778e+00 8.888889e+00 1.000000e+01 0.000000e+00 1.111111e+00 2.222222e+00 3.333333e+00 4.444445e+00 5.555555e+00 6.666667e+00 7.777778e+00 8.888889e+00 1.000000e+01 0.000000e+00 1.111111e+00 2.222222e+00 3.333333e+00 4.444445e+00 5.555555e+00 6.666667e+00 7.777778e+00 8.888889e+00 1.000000e+01 0.000000e+00 1.111111e+00 2.222222e+00 3.333333e+00 4.444445e+00 5.555555e+00 6.666667e+00 7.777778e+00 8.888889e+00 1.000000e+01...and so on... 

我可以读取前4个整数,因此我知道我希望存储数据的点数。 然后我使用malloc函数来分配内存并将数据存储在变量中。 当我执行程序时,它读取整数但无法读取双精度数。 我犯的错是什么?

这是我的代码:

 #include  #include  typedef struct{ double x,y,z; }Mesh; int main(void) { int nblocks, IMAX, JMAX, KMAX; Mesh ***grid; FILE *mesh = fopen("test.x","r"); fscanf(mesh,"%i %i %i %i",&nblocks,&IMAX,&JMAX,&KMAX); printf("%i %i %i %i\n",nblocks,IMAX,JMAX,KMAX); grid = malloc(sizeof(Mesh)*nblocks*IMAX*JMAX*KMAX); fscanf(mesh,"%lf",&grid[0][0][0].x); printf("%lf\n",grid[0][0][0].x); fclose(mesh); return 0; } 

编译时程序不会产生任何错误,但它不会读取/写入存储在struct的x变量中的变量。 (如果这样可行,我可以将它放在循环中以读取我在这里没有完成的所有值。)

如果我在读入IMAX,JMAX,KMAX后定义Mesh grid[IMAX][JMAX][KMAX] ,我得到正确的输出。 但是想知道指针的工作方式。

谢谢你,Pranav

你有一个四维数组,而不是三个。 尺寸是:

  1. nblocks
  2. IMAX
  3. JMAX
  4. KMAX

因此, grid的类型必须是Mesh**** ,而不是Mesh***

 Mesh ****grid; 

grid分配内存的代码必须是:

 grid = malloc(nblocks * (sizeof *grid)); for ( block = 0; block < nblocks; ++block ) { grid[block] = malloc(IMAX * (sizeof *grid[0])); for ( i = 0; i < IMAX ; ++i ) { grid[block][i] = malloc(JMAX * (sizeof *grid[0][0])); for ( j = 0; j < JMAX ; ++j ) { grid[block][i][j] = malloc(KMAX * (sizeof *grid[0][0][0])); } } } 

现在,您可以使用以下方法访问网格数据:

 grid[block][index][jindex][kindex] 

这些是有效的用法:

 fscanf(mesh,"%lf",&grid[0][0][0][0].x); printf("%lf\n",grid[0][0][0][0].x); 

问题是您将网格定义为指向指向struct的指针的指针,但您认为您有一个连续元素的三维数组。

错误的解释

以下数组:

 Mesh array[10][5][1]; // what you would like to manage dynamically 

将存储在内存中,如下所示:

 +----+----+----+----+----+----+----+----+----+----+----+----+----- |A000|A010|A020|A020|A030|A040|A100|A110|A120|A120|1030|A140|.... +----+----+----+----+----+----+----+----+----+----+----+----+----- 

但是下面指向指针的指针

 Mesh ***grid; // How you decladed it 

管理就像它会像这样:

 grid--> +--+--+--+--+--+--+--+ | 0| 1| 2|........| 9| some pointers to "pointers to struct" +--+--+--+--+--+--+--+ grid[0] | +---> +--+--+------+ | 1| 2| .... | some pointers to struct +--+--+------+ grid[0][0] | +---> +--+--+------+ | 1| 2| .... | some struct +--+--+------+ grid[0][0][0] | +---> +----+----+----+---- |A000|A010|A020|... some struct +----+----+----+---- 

您的malloc()分配一组连续的IMAX * JMAX * KMAX结构元素。 实际上,它就像一维数组,因为malloc()和你的编译器对维度及其相应的大小一无所知。

但是当你编写网格[0]时,你的代码会查看网格指向的地址,并期望在那里找到一个指针(但它只是未初始化的结构),依此类推。 因此,您可能会在内存中的随机位置写入并获得分段错误。

您必须将网格作为一维结构数组进行管理,并在代码中明确地组织索引。

所以声明:

 Mesh *grid; 

每当你想到你的网格的元素[i] [j] [k]时,写下:

 grid[(i*JMAX+j)*KMAX+k] 

杂项评论:

您可以使用calloc(IMAX*JMAX*KMAX, sizeof(Mesh))因为它表明它是一个数组,并且内存块设置为0。

顺便说一句,(可能你已经在你的真实代码中已经有了它)作为reflection总是检查分配是否成功,并且当你不再需要它时预见到free()。

一个简单的选择是写:

 Mesh (*grid)[IMAX][JMAX][KMAX] = malloc( nblocks * sizeof *grid ); 

然后访问项目:

 grid[block_num][i][j][k] = 5; 

你在评论中指出你并不真正需要nblocks因为它总是1 ,在这种情况下你可以去:

 Mesh (*grid)[JMAX][KMAX] = malloc( IMAX * sizeof *grid ); // ... grid[i][j][k] = 5; 

从C99开始,允许数组维度不是编译时常量。 1

注意使用idiom ptr = malloc(N * sizeof *ptr); ,这保证了我们分配了任何类型的ptr指向的N ,所以我们可以确定我们分配了正确的字节数,即使ptr的类型很复杂。


1此function在C99中是必需的,但在C11中已更改为可选。 如果您使用符合C11但没有VLA(我不知道任何)的编译器,您将不得不选择其他解决方案之一。