Question

I know about algorithms to allocate/deallocate a 2D array dynamically, however I'm not too sure about the same for 3D arrays.
Using this knowledge and a bit of symmetry, I came up with the following code.
(I had a hard time visualizing in 3D during coding).

Please comment on the correctness and suggest any better alternative (efficiency-wise or intuitively), if any.
Also, I think both these 2D and 3D arrays can be accessed normally like static arrays like arr2D[2][3] and
arr3D[2][3][2]. Right?

Code for 2D

//allocate a 2D array
int** allocate2D(int rows,int cols)
{
    int **arr2D;
    int i;

    arr2D = (int**)malloc(rows*sizeof(int*));
    for(i=0;i<rows;i++)
    {
        arr2D[i] = (int*)malloc(cols*sizeof(int));
    }
}

//deallocate a 2D array
void deallocate2D(int** arr2D,int rows)
{
    int i;

    for(i=0;i<rows;i++)
    {
        free(arr2D[i]);
    }

    free(arr2D);
}  

Code for 3D

//allocate a 3D array
int*** allocate3D(int l,int m,int n)
{
int ***arr3D;
int i,j,k;

arr3D = (int***)malloc(l * sizeof(int **));

for(i=0;i<l;i++)
{
    arr3D[i] = (int**)malloc(m * sizeof(int*));
    for(j=0;j<m;j++)
    {
        arr3D[i][j] = (int*)malloc(n*sizeof(int));
    }
}

return arr3D;
}

//deallocate a 3D array
void deallocate3D(int arr3D,int l,int m)
{
    int i,j;

    for(i=0;i<l;i++)
    {
        for(int j=0;j<m;j++)
        {
            free(arr3D[i][j]);
        }
        free(arr3D[i]);
    }
    free(arr3D);
}
Was it helpful?

Solution

You can also allocate one array and compute individual indices. This requires fewer allocator calls and results in both less fragmentation and better cache use.

typedef struct {
  int a;
  int b;
  int* data;
} Int2d;

Int2d arr2d = { 2, 3 };
arr2d.data = malloc(arr2d.a * arr2d.b * sizeof *arr2d.data);

Now arr2d[r][c] becomes arr2d.data[r * arr2d.b + c]. Deallocation is a single free() away. As a bonus you're sure to always keep your dynamic array sizes with you.

Extrapolating to 3d:

typedef struct {
  int a;
  int b;
  int c;
  int* data;
} Int3d;

Int3d arr3d = { 2, 3, 4 };
arr3d.data = malloc(arr3d.a * arr3d.b * arr3d.c * sizeof *arr3d.data);

//arr3d[r][c][d]
// becomes:
arr3d.data[r * (arr3d.b * arr3d.c) + c * arr3d.c + d];

You should encapsulate these index operations (and the (de-)allocations for that matter) in a separate function or macro.

(The names for r, c, and d could be better—I was going for row, column, and depth. While a, b, and c are the limits of their corresponding dimensions, you might prefer something like n1, n2, n3 there, or even use an array for them.)

OTHER TIPS

arr3d should be a triple pointer and not just an int. Otherwise looks OK:

void deallocate3D(int*** arr3D,int l,int m)
{
    int i,j;

    for(i=0;i<l;i++)
    {
        for(int j=0;j<m;j++)
        {
                free(arr3D[i][j]);
        }
        free(arr3D[i]);
    }
    free(arr3D);
}

arr3D is a pointer-to-pointer-to-pointer, so arr3D[i] is a pointer-to-pointer and arr3D[i][j] just a pointer. It's correct to release the lowest dimension in a loop first, and then climb up the dimensions until arr3D itself is released.

Also it's more idiomatic to give malloc the sizeof of the pointed type implicitly. Instead of:

  arr3D[i] = (int**)malloc(m * sizeof(int*));

Make it:

  arr3D[i] = (int**)malloc(m * sizeof(*arr3D[i]));

And yes, such dynamically allocated multi-dimensional arrays can be accessed just as statically allocated multi-dimensional arrays.

You can see the below code:

#include <stdio.h>
#include <stdlib.h>

void main()
{
    //  Array 3 Dimensions
    int x = 4, y = 5, z = 6;

    //  Array Iterators
    int i, j, k;

    //  Allocate 3D Array
    int *allElements = malloc(x * y * z * sizeof(int));
    int ***array3D = malloc(x * sizeof(int **));

    for(i = 0; i < x; i++)
    {
        array3D[i] = malloc(y * sizeof(int *));

        for(j = 0; j < y; j++)
        {
            array3D[i][j] = allElements + (i * y * z) + (j * z);
        }
    }

    //  Access array elements
    for(i = 0; i < x; i++)
    {
        printf("%d\n", i);

        for(j = 0; j < y; j++)
        {
            printf("\n");

            for(k = 0; k < z; k++)
            {
                array3D[i][j][k] = (i * y * z) + (j * z) + k;
                printf("\t%d", array3D[i][j][k]);
            }
        }

        printf("\n\n");
    }

    //  Deallocate 3D array
    free(allElements);
    for(i = 0; i < x; i++)
    {
        free(array3D[i]);
    }
    free (array3D);
}

For more details see this link 3d array

This is a version of the idea in the question but using only one malloc, inspired by the other answers. It allows intuitive use of the square brackets and easy cleaning. I hope it does not make any compiler implementation specific assumption.

int main(int argc, char *argv[])
{
  int **array, i, j;
  array = allocate2d(3, 4);
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      array[i][j] = j + i + 1;
    }
  }
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 4; j++)
    {
      printf("array[%d][%d] = %d\n", i, j, array[i][j]);
    }
  }
  free(array);
  return EXIT_SUCCESS;
}

int **allocate2d(int x, int y)
{
  int i;
  int **array = malloc(sizeof(int *) * x + sizeof(int) * x * y);
  for (i = 0; i < x; i++)
  {
    array[i] = ((int *)(array + x)) + y * i;
  }
  return array;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top