这可能是一个基本问题,但我想为结构的三维数组分配内存。我正在尝试从文件中读取替身,并希望存储在结构中。第一行是块编号(此处不相关,因为它总是1),第二行分别表示X、Y和Z坐标中的网格点数量。在这种情况下,X方向上有10个点,Y方向上有5个点,Z方向上有1个点。从第三行开始,是每个点的X,Y,Z坐标,这是我想读的二重。首先是所有的X分量(即10*5*1x坐标,然后是类似的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 <stdio.h>
#include <stdlib.h>
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 %in",nblocks,IMAX,JMAX,KMAX);
grid = malloc(sizeof(Mesh)*nblocks*IMAX*JMAX*KMAX);
fscanf(mesh,"%lf",&grid[0][0][0].x);
printf("%lfn",grid[0][0][0].x);
fclose(mesh);
return 0;
}
该程序在编译时没有给出任何错误,但它不会读/写我存储在结构的x变量中的变量。(如果这有效,我可以将其放入循环中,以读取我在这里没有完成的所有值。)
如果我在读取IMAX,JMAX,KMAX
之后定义了Mesh grid[IMAX][JMAX][KMAX]
,我会得到正确的输出。但想知道指针式的工作方式是如何工作的。
谢谢,Pranav
问题是,您将网格定义为指向指向结构的指针的指针,但您认为您有一个连续元素的三维数组。
错误解释
以下阵列:
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()和编译器对维度及其相应的大小一无所知。
但是当你写grid[0]时,你的代码会查看grid指向的地址,并期望在那里找到一个指针(但它只是未初始化的结构)等等。所以你可能会在内存中的一个随机位置写,然后出现分段错误。
解决方案
您必须将网格管理为结构的一维数组,并在代码中明确组织索引。
因此声明:
Mesh *grid;
每当你想到网格的元素[i][j][k]时,写下:
grid[(i*JMAX+j)*KMAX+k]
其他备注:
您可以使用calloc(IMAX*JMAX*KMAX, sizeof(Mesh))
,因为它清楚地表明它是一个数组,并且内存块设置为0。
顺便说一句,(可能你的真实代码中已经有了)作为一种反射,总是检查分配是否成功,并在你不再需要时预见一个free()。
您有一个四维数组,而不是三维数组。尺寸为:
nblocks
IMAX
JMAX
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("%lfn",grid[0][0][0][0].x);
一个简单的选项是写入:
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
注意成语ptr = malloc(N * sizeof *ptr);
的使用,这保证了我们分配ptr
指向的任何类型的N
,因此我们可以确保,即使ptr
的类型很复杂,我们也分配了正确数量的字节。
1C99需要此功能,但在C11中更改为可选功能。如果你使用的编译器是C11兼容的,但没有VLA(我不知道有),你必须选择其他解决方案之一。
小时>