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

时间:2022-09-06 11:26:48

This is probably a basic question but I want to allocate the memory for 3 dimensional array of a struct. I'm trying to read doubles from a file and want to store in struct. The first line is block number (not relevant here as it'll be 1 always), second line denotes the number of grid points in X, Y and Z coordinate respectively. In this case 10 points in X, 5 in Y and 1 in Z direction. And from third line, are the X,Y,Z coordinates of each points which are the doubles I would like to read. First there are all X components (i.e. 10*5*1 x coordinates, then similarly Y and Z). The file format is like this:

这可能是一个基本问题,但我想为结构的三维数组分配内存。我正在尝试从文件中读取双打并想要存储在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...

I can read the first 4 integers and hence I know the number of points I wish to store data for. Then I'm using malloc function to allocate the memory and store the data in the variables. When I execute the program, it reads the integers but fails to read the doubles. What is the mistake I'm making?

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

Here's my code:

这是我的代码:

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

The program doesn't give any error while compiling but it does't read/write the variable I stored in the x variable of the struct. (If this works, I can put it in loop for reading all values which I've not done here.)

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

If I define Mesh grid[IMAX][JMAX][KMAX] after I read in IMAX,JMAX,KMAX, I get correct output. But wanted to know how pointer way of doing works.

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

Thank you, Pranav

谢谢你,Pranav

3 个解决方案

#1


2  

You have a four dimensional array, not three. The dimensions are:

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

  1. nblocks
  2. 的nblocks
  3. IMAX
  4. IMAX
  5. JMAX
  6. JMAX
  7. KMAX
  8. KMAX

Hence, the type for grid has to be Mesh****, not Mesh***.

因此,网格的类型必须是Mesh ****,而不是Mesh ***。

Mesh ****grid;

Your code to allocate memory for grid has to be:

为网格分配内存的代码必须是:

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

Now, you can access the grid data using:

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

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

These are valid usages:

这些是有效的用法:

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

#2


3  

The problem is that you define grid as a pointer to a pointer to a pointer to struct, but you think that you have a three dimensional array of contiguous elements.

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

Explanation of the error

错误的解释

The following array:

以下数组:

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

would be stored in memory like this:

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

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

But the following pointer to pointer to pointer

但是下面指向指针的指针

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

is managed as if it would be like this:

管理就像它会像这样:

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  
                                    +----+----+----+----

Your malloc() allocates an array of contiguous IMAX*JMAX*KMAX struct elements. In reality, it's like a one dimensional array, because malloc() and your compiler do not know anything about the dimensions and their respecive size.

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

But when you write grid[0], your code looks at the adress pointed to by grid and expects to find a pointer there (but it's yet only uninitialised struct) and so on. So you might write at a random place in memory and get a segmentation fault.

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

Solution

You must manage grid as a one dimentional array of struct, and organise the indexing explicitely in your code.

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

So declare:

所以声明:

Mesh *grid; 

And whenever you think of element [i][j][k] of your mesh, write:

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

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

Miscellaneous remarks:

杂项评论:

You could use calloc(IMAX*JMAX*KMAX, sizeof(Mesh)) because it makes clear that it's an array, and the memory bloc is set to 0.

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

By the way, (may be you have it already in your real code) as a reflex always check if the allocation succeeds, and foresee a free() when you no longer need it.

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

#3


2  

A simple option is to write:

一个简单的选择是写:

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

Then to access the items:

然后访问项目:

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

You indicated in a comment that you don't really need the nblocks since it is always 1, in that case you could go:

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

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

Since C99 it is permitted for array dimensions to not be compile-time constants. 1

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

Note the use of the idiom ptr = malloc(N * sizeof *ptr);, this guarantees that we allocate N of whatever type ptr points to, so we can be sure that we allocated the right number of bytes even though the type of ptr is complicated.

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


1This feature was required in C99 but changed to optional in C11. If you are on a compiler that is C11 compliant but does not have VLA (I don't know of any) you would have to go for one of the other solutions.

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

#1


2  

You have a four dimensional array, not three. The dimensions are:

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

  1. nblocks
  2. 的nblocks
  3. IMAX
  4. IMAX
  5. JMAX
  6. JMAX
  7. KMAX
  8. KMAX

Hence, the type for grid has to be Mesh****, not Mesh***.

因此,网格的类型必须是Mesh ****,而不是Mesh ***。

Mesh ****grid;

Your code to allocate memory for grid has to be:

为网格分配内存的代码必须是:

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

Now, you can access the grid data using:

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

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

These are valid usages:

这些是有效的用法:

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

#2


3  

The problem is that you define grid as a pointer to a pointer to a pointer to struct, but you think that you have a three dimensional array of contiguous elements.

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

Explanation of the error

错误的解释

The following array:

以下数组:

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

would be stored in memory like this:

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

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

But the following pointer to pointer to pointer

但是下面指向指针的指针

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

is managed as if it would be like this:

管理就像它会像这样:

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  
                                    +----+----+----+----

Your malloc() allocates an array of contiguous IMAX*JMAX*KMAX struct elements. In reality, it's like a one dimensional array, because malloc() and your compiler do not know anything about the dimensions and their respecive size.

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

But when you write grid[0], your code looks at the adress pointed to by grid and expects to find a pointer there (but it's yet only uninitialised struct) and so on. So you might write at a random place in memory and get a segmentation fault.

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

Solution

You must manage grid as a one dimentional array of struct, and organise the indexing explicitely in your code.

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

So declare:

所以声明:

Mesh *grid; 

And whenever you think of element [i][j][k] of your mesh, write:

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

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

Miscellaneous remarks:

杂项评论:

You could use calloc(IMAX*JMAX*KMAX, sizeof(Mesh)) because it makes clear that it's an array, and the memory bloc is set to 0.

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

By the way, (may be you have it already in your real code) as a reflex always check if the allocation succeeds, and foresee a free() when you no longer need it.

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

#3


2  

A simple option is to write:

一个简单的选择是写:

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

Then to access the items:

然后访问项目:

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

You indicated in a comment that you don't really need the nblocks since it is always 1, in that case you could go:

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

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

Since C99 it is permitted for array dimensions to not be compile-time constants. 1

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

Note the use of the idiom ptr = malloc(N * sizeof *ptr);, this guarantees that we allocate N of whatever type ptr points to, so we can be sure that we allocated the right number of bytes even though the type of ptr is complicated.

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


1This feature was required in C99 but changed to optional in C11. If you are on a compiler that is C11 compliant but does not have VLA (I don't know of any) you would have to go for one of the other solutions.

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