简体   繁体   中英

How to allocate and declare a 3D of array of structs in C?

How do you allocate and declare a 3D array of structs in C? Do you first allocate the array or declare it? I feel like you have to allocate it first so you can declare it so it is on the heap, but then how do you allocate something that hasn't been made yet? Also, should you allocate it all at once or element by element? Also am i putting the structs into the array correctly? My guess on how to do it would be:

header.h

struct myStruct{
   int a;
   int b;
}; 
typedef struct myStruct myStruct_t;

main.c

#include "header.h"
#include <stdio.h>
#include <stdlib.h>
int main(void){

    int length=2;
    int height=3;
    int width =4;
    myStruct_t *elements;
    struct myStruct arr = (*myStruct_t) calloc(length*height*width, sizeof(myStruct);
    //zero based array
    arr[length-1][height-1][width-1];

    int x=0;
    while(x<length){
        int y=0;
        while(y<height){
            int z=0;
            while(z<depth){
                arr[x][y][z].a=rand();
                arr[x][y][z].b=rand();
                z++;
            }
            y++;
        }
        x++;
    }
    return 0;
}    

There are a couple of different ways to do this, depending on what you want. First, you can allocate your array on the stack (in C99 and some compilers) like this:

myStruct_t arr[length][height][depth];

If you want it allocated on the heap, then you can do a single allocation of the appropriate size. You can then either do the index calculation yourself or make a pointer do the work for you (in C99 and some compilers):

void *buf = malloc(length * height * width * sizeof(myStruct_t));
myStruct_t *arr = buf;
myStruct_t (*arr2)[height][width] = buf;

/* TODO: check return of malloc */
...

arr[x * height * width + y * width + z].a = rand();  /* indexing the C89 way */
arr2[x][y][z].b = rand();                            /* indexing the C99 way */

Or you can manually allocate the multiple dimensions.

#include <stddef.h>
#include <stdlib.h>

typedef struct myStruct
{
  int a, b;

} myStruct_t;

int main()
{
  myStruct_t ***arr;
  int length = 5000, height = 1000, depth = 20;
  int x, y, z;
  int ret = 1;

  if (NULL == (arr = malloc(length * sizeof(myStruct_t**))))
    goto FAIL;

  for (x = 0; x < length; ++x)
  {
    if (NULL == (arr[x] = malloc(height * sizeof(myStruct_t*))))
      goto FAIL_X;

    for (y = 0; y < height; ++y)
    {
      if (NULL == (arr[x][y] = malloc(depth * sizeof(myStruct_t))))
        goto FAIL_Y;

      for (z = 0; z < depth; ++z)
      {
        arr[x][y][z].a = rand();
        arr[x][y][z].b = rand();
      }
    }
  }

  /* TODO: rest of program logic */

  /* program successfully completed */

  ret = 0;

  /* reclaim arr */

FAIL_CLEANUP: /* label used by TODO code that fails */

  for (x = length - 1; x >= 0; --x)
  {
    for (y = height - 1; y >= 0; --y)
    {
      free(arr[x][y]);
    FAIL_Y:
      ;
    }

    free(arr[x]);
  FAIL_X:
    ;
  }

  free(arr);

FAIL:    
  return ret;
}

This last version uses a lot more memory for all the explicit pointers it contains, its memory locality is worse and it's significantly more complex to properly allocate and reclaim. However, it does allow different sizes along your dimensions. For example, the array arr[0][4] can have a different size than arr[0][7] if you ever need that.

If you want to allocate it on the heap, then you probably want the second version with a single allocation and multi-dimension pointer (if available) or do the indexing yourself manually using appropriate math.

The easy way is:

 myStruct_t (*arr2)[height][width] = calloc( length * sizeof *arr );

Then your loop can access arr2[x][y][z].a = rand(); and so on. If you're not familiar with this way of calling calloc , see here . As usual with malloc, check arr2 against NULL before proceeding.

The triple-pointer approach is not really a practical solution. If your compiler does not support variably-modified types then the array should be flattened to 1-D.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM