asignación/desasignación dinámica de arreglos 2D y 3D

5 minutos de lectura

Conozco algoritmos para asignar/desasignar dinámicamente una matriz 2D, sin embargo, no estoy muy seguro de lo mismo para las matrices 3D.
Usando este conocimiento y un poco de simetría, se me ocurrió el siguiente código.
(Me costó mucho visualizar en 3D durante la codificación).

Comente sobre la corrección y sugiera cualquier alternativa mejor (en términos de eficiencia o intuitivamente), si corresponde.
Además, creo que se puede acceder a estas matrices 2D y 3D normalmente como matrices estáticas como arr2D[2][3] y
Arr3D[2][3][2]. ¿Derecha?

Código para 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);
}  

Código para 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);
}

También puede asignar una matriz y calcular índices individuales. Esto requiere menos llamadas al asignador y da como resultado una menor fragmentación y un mejor uso de la memoria caché.

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

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

Ahora arr2d[r][c] se convierte arr2d.data[r * arr2d.b + c]. La desasignación está a un solo free() de distancia. Como beneficio adicional, puede estar seguro de que siempre llevará consigo los tamaños de sus arreglos dinámicos.

Extrapolando a 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];

Debe encapsular estas operaciones de índice (y las (desasignaciones) para el caso) en una función o macro separada.

(Los nombres para r, c y d podrían ser mejores: yo iba por fila, columna y profundidad. Mientras que a, b y c son los límites de sus dimensiones correspondientes, es posible que prefiera algo como n1, n2, n3 allí, o incluso usar una matriz para ellos).

  • también puede asignar una matriz n dimensional en un solo bloque lo suficientemente grande como para contener punteros y datos. De esa manera puede ir int ***** array = allocate (sizeof(int), 10, 10, 10, 10, 10, 0); para asignar una matriz int 5D e indexarla por matriz [a][b][c][d][e] sin necesidad de calcular los índices. Utilicé esto cuando necesitaba reemplazar matrices de pilas grandes con montones para codificar para trabajar en teléfonos con un tamaño de pila limitado sin necesidad de hacer un ajuste serio al código que indexa las matrices. Mira aquí: sourceforge.net/p/gnugos60/code/HEAD/tree/trunk/GNUGoS60/common/…

    – idij

    3 de agosto de 2016 a las 10:49

  • El único problema con hacer la multiplicación parece ser el potencial de desbordamiento. Al igual que hay un reallocarray en BSD unixes como reemplazo de la función realloc.

    – reportero

    27 de noviembre de 2021 a las 2:13


arr3d debe ser un puntero triple y no solo un int. De lo contrario se ve bien:

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 es un puntero a puntero a puntero, entonces arr3D[i] es un puntero a puntero y arr3D[i][j] solo un puntero. Es correcto liberar primero la dimensión más baja en un ciclo y luego subir las dimensiones hasta que se libere arr3D.

También es más idiomático dar malloc el tamaño del tipo puntiagudo implícitamente. En lugar de:

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

Hazlo:

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

Y sí, se puede acceder a tales arreglos multidimensionales asignados dinámicamente al igual que a los arreglos multidimensionales asignados estáticamente.

Puedes ver el siguiente código:

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

Para más detalles ver este enlace matriz 3d

Esta es una versión de la idea en la pregunta pero usando solo un malloc, inspirado en las otras respuestas. Permite un uso intuitivo de los corchetes y una fácil limpieza. Espero que no haga ninguna suposición específica de implementación del compilador.

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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad