Saltar al contenido

¿Cómo trabajo con arreglos multidimensionales dinámicos en C?

Leila, parte de este gran staff, nos ha hecho el favor de crear este enunciado porque conoce perfectamente este tema.

Solución:

Desde C99, C tiene matrices 2D con límites dinámicos. Si desea evitar que tales bestias se asignen en la pila (que debería), puede asignarlas fácilmente de una vez de la siguiente manera

double (*A)[n] = malloc(sizeof(double[n][n]));

y eso es. Luego puede usarlo fácilmente como lo usa para matrices 2D con algo como A[i][j]. Y no olvides que uno al final

free(A);

Randy Meyers escribió una serie de artículos explicando matrices de longitud variable (VLA).

Con asignación dinámica, usando malloc:

int** x;

x = malloc(dimension1_max * sizeof(*x));
for (int i = 0; i < dimension1_max; i++) 
  x[i] = malloc(dimension2_max * sizeof(x[0]));


//Writing values
x[0..(dimension1_max-1)][0..(dimension2_max-1)] = Value; 
[...]

for (int i = 0; i < dimension1_max; i++) 
  free(x[i]);

free(x);

Esto asigna un 2D array de tamaño dimension1_max * dimension2_max. Entonces, por ejemplo, si quieres un 640*480 array (pe píxeles de una imagen), utilice dimension1_max = 640, dimension2_max = 480. A continuación, puede acceder a la array utilizando x[d1][d2] donde d1 = 0..639, d2 = 0..479.

Pero una búsqueda en SO o Google también revela otras posibilidades, por ejemplo en esta pregunta SO

Tenga en cuenta que su array no asignará una región contigua de memoria (640*480 bytes) en ese caso, lo que podría generar problemas con las funciones que asumen esto. Así que para obtener el array cumpla la condición, reemplace el bloque malloc de arriba con esto:

int** x;
int* temp;

x = malloc(dimension1_max * sizeof(*x));
temp = malloc(dimension1_max * dimension2_max * sizeof(x[0]));
for (int i = 0; i < dimension1_max; i++) 
  x[i] = temp + (i * dimension2_max);


[...]

free(temp);
free(x);

Lo esencial

Los arreglos en c son declarados y accedidos usando el [] operador. Así que eso

int ary1[5];

declara un array de 5 enteros. Los elementos se numeran desde cero por lo que ary1[0] es el primer elemento y ary1[4] es el último elemento. Nota 1: No hay una inicialización predeterminada, por lo que la memoria ocupada por el array inicialmente puede contener cualquier cosa. Nota 2: ary1[5] accede a la memoria en un estado indefinido (que puede que ni siquiera sea accesible para usted), ¡así que no lo haga!

Los arreglos multidimensionales se implementan como un array de arreglos (de arreglos (de ... ) ). Entonces

float ary2[3][5];

declara un array de 3 arreglos unidimensionales de 5 números de coma flotante cada uno. Ahora ary2[0][0] es el primer elemento del primero array, ary2[0][4] es el último elemento del primero arrayy ary2[2][4] es el último elemento del último array. El estándar '89 requiere que estos datos sean contiguos (sec. A8.6.2 en la página 216 de mi K&R 2nd. ed.) pero parece ser agnóstico en el relleno.

Tratando de ser dinámico en más de una dimensión

Si no sabes el tamaño de la array en tiempo de compilación, querrá asignar dinámicamente el array. Es tentador probar

double *buf3;
buf3 = malloc(3*5*sizeof(double));
/* error checking goes here */

que debería funcionar si el compilador no rellena la asignación (pegue espacio adicional entre las matrices unidimensionales). Podría ser más seguro ir con:

double *buf4;
buf4 = malloc(sizeof(double[3][5]));
/* error checking */

pero de cualquier manera, el truco viene en el momento de la desreferenciación. no puedes escribir buf[i][j] porque buf tiene el tipo incorrecto. Tampoco puedes usar

double **hdl4 = (double**)buf;
hdl4[2][3] = 0; /* Wrong! */

porque el compilador espera hdl4 ser la dirección de una dirección de un doble. Tampoco puedes usar double incomplete_ary4[][]; porque esto es un error;

¿Entonces que puedes hacer?

  • Haz tú mismo la aritmética de filas y columnas
  • Asignar y hacer el trabajo en una función
  • Usa un array de punteros (el mecanismo del que habla qrdl)

Haz los cálculos tú mismo

Simplemente calcule el desplazamiento de memoria para cada elemento de esta manera:

  for (i=0; i<3; ++i)
     for(j=0; j<3; ++j)
        buf3[i * 5 + j] = someValue(i,j); /* Don't need to worry about 
                                             padding in this case */
     
  

Asignar y hacer el trabajo en una función

Defina una función que tome el tamaño necesario como argumento y proceda normalmente

void dary(int x, int y)
  double ary4[x][y];
  ary4[2][3] = 5;

Por supuesto, en este caso ary4 es una variable local y no se puede devolver: todo el trabajo con el array debe hacerse en la función a la que llama en funciones que eso llamadas

Un array de punteros

Considera esto:

double **hdl5 = malloc(3*sizeof(double*));
/* Error checking */
for (i=0; i<3; ++i)
   hdl5[i] = malloc(5*sizeof(double))
   /* Error checking */

Ahora hdl5 apunta a un array de punteros, cada uno de los cuales apunta a un array de dobles. Lo bueno es que puedes usar el bidimensional array notación para acceder a esta estructura---hdl5[0][2] obtiene el elemento del medio de la primera fila --- pero este es, sin embargo, un tipo de objeto diferente a un objeto bidimensional array declarado por double ary[3][5];.

Esta estructura es más flexible que una bidimensional. array (porque las filas no necesitan tener la misma longitud), pero el acceso generalmente será más lento y requiere más memoria (necesita un lugar para colocar los punteros intermedios).

Tenga en cuenta que, dado que no he configurado ningún protector, tendrá que realizar un seguimiento del tamaño de todas las matrices usted mismo.

Aritmética

c no proporciona soporte para matemáticas vectoriales, matriciales o tensoriales, tendrá que implementarlo usted mismo o traer una biblioteca.

La multiplicación por un escalador y la suma y resta de matrices del mismo rango son fáciles: simplemente recorra los elementos y realice la operación sobre la marcha. Los productos internos son igualmente sencillos.

Los productos exteriores significan más bucles.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *