Malloc a 3-Dimensional array in C?

后端 未结 13 854
余生分开走
余生分开走 2020-11-28 07:56

I\'m translating some MATLAB code into C and the script I\'m converting makes heavy use of 3D arrays with 10*100*300 complex entries. The size of the array also depends on t

相关标签:
13条回答
  • 2020-11-28 08:12

    This should work, you are not typecasting the return value of malloc

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

    Working Link: http://ideone.com/X2mcb8

    0 讨论(0)
  • 2020-11-28 08:14

    In this way you can allocate only just 1 block of memory and the dynamic array behaves like the static one (i.e. same memory contiguity). You can also free memory with a single free(array) like ordinary 1-D arrays.

    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;
    }
    
    0 讨论(0)
  • 2020-11-28 08:14

    You are forcing yourself into perceiving this as two fundamentally different ways to allocate a 3D array. This perception is reinforced by two definitive differentiating details: 1) the second method uses several levels of indirection to access the actual elements, 2) the second method allocates the lower-level 1D arrays independently.

    But why exactly do you insist on allocating the lower-level 1D arrays independently? You don't have to do that. And once you take it into account, you should realize that there's a third method of building your 3D array

    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;
    

    If you look at this allocation method closely, you should see that in the end this is pretty much the same thing as your second method: it builds a three-level array structure by using intermediate pointers at each level of indirection. The only difference is that it pre-allocates memory for each level of indirection contiguously, "in one shot", beforehand, instead of making multiple repetitive malloc calls. The subsequent cycle simply distributes that pre-allocated memory among the sub-arrays (i.e. it simply initializes the pointers).

    However, if you look even closer, you'll also notice that the actual array element memory (the ints that store actual the values) are allocated in exactly the same way as they would be in your first method: malloc(3 * 3 * 3 * sizeof(int)); - as a plain flat contiguous array.

    Now, if you think about it, you should realize that this third method is not much different from your first. They both use a flat array of size xSize * ySize * zSize to store the data. The only real difference here is the method we use to calculate the index to access that flat data. In the first method we'd calculate the index on-the-fly as

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

    in the third method we pre-calculate the pointers to array elements in advance, using essentially the same formula, store the pre-calculated results in additional arrays and retrieve them later using the "natural" array access syntax

    array3d[x][y][x]
    

    The question here is whether this pre-calculation is worth the extra effort and extra memory. The answer is: generally no, it is not. By spending this extra memory you will not reap any appreciable performance benefits (chances are it will make your code slower).

    The only situation where your second method might be worth considering is when you are dealing with genuinely jagged/ragged array: a sparse multi-dimensional array with some sub-arrays parts missing/unused or having reduced size. For example, if some 1D or 2D sub-arrays of your 3D array are known to contain just zeros, you might decide not to store them in memory at all and set the corresponding pointers to null. This would imply using your second method, where the sub-arrays are allocated (or not allocated) independently. If the data is large the resultant memory savings could be well worth it.

    Also note that when we are talking about arrays with 3 and more dimensions, the first/second/third allocation methods can be used together, simultaneously for different levels of indirection. You might decide to implement 2D arrays using the first method and then combine them into a 3D array using the second method.

    0 讨论(0)
  • 2020-11-28 08:14
    #include<stdio.h>
    #include<stdlib.h>
    
    #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 >;
    
    }
    
    0 讨论(0)
  • 2020-11-28 08:19

    I'd go for the first option (the single 1D array) as it will give you a single block of memory to play in rather than potentially thousands of fragmented memory blocks

    If accessing the correct element of the array is doing your head in though, I'd write a utility method to convert x, y, z locations into an offset into the 1D array

    int offset(int x, int y, int z) { 
        return (z * xSize * ySize) + (y * xSize) + x; 
    }
    
    0 讨论(0)
  • 2020-11-28 08:23

    Oh do I hate malloc array allocation ^^

    Here's a correct version, basically it was just one incorrect line:

    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;
    }
    
    0 讨论(0)
提交回复
热议问题