asignación dinámica de matrices en C

Realmente no entiendo algunas cosas básicas en C como la asignación dinámica de una matriz de matrices. Sé que puedes hacer:

int **m; 

para declarar una matriz bidimensional (que posteriormente se asignaría usando alguna función * alloc). También se puede acceder “fácilmente” haciendo *(*(m + line) + column) . Pero, ¿cómo debería asignar un valor a un elemento de esa matriz? Usando gcc la siguiente instrucción m[line][column] = 12; falla con una falla de segmentación

Cualquier artículo / documentación será apreciado. 🙂

La syntax m[line][column] = 12 está bien (siempre que la line y la column estén dentro del rango).

Sin embargo, no escribió el código que usa para asignarlo, por lo que es difícil saber si está equivocado o no. Debería ser algo así como

 m = (int**)malloc(nlines * sizeof(int*)); for(i = 0; i < nlines; i++) m[i] = (int*)malloc(ncolumns * sizeof(int)); 

Algunas notas secundarias:

  • De esta manera, puede asignar cada línea con una longitud diferente (por ejemplo, una matriz triangular)
  • Puede realloc () o free () una línea individual más tarde mientras usa la matriz
  • Debes liberar () cada línea, cuando liberas () toda la matriz

Su syntax m [línea] [columna] es correcta. Pero para usar una matriz 2D en C, debe asignarle memoria. Por ejemplo, este código asignará memoria para una tabla de línea y columna determinada.

 int** AllocateArray(int line, int column) { int** pArray = (int**)malloc(line*sizeof(int*)); for ( int i = 0; i < line; i++ ) { pArray[i] = (int*)malloc(column*sizeof(int)); } return pArray; } 

Tenga en cuenta, omití las comprobaciones de error de Malloc para abreviar. Una solución real debería incluirlos.

No es una matriz 2D, es una matriz de matrices, por lo tanto, necesita las múltiples asignaciones.

Aquí hay una versión modificada de la solución de quinmars que solo asigna un solo bloque de memoria y se puede usar con valores generics por cortesía de void * :

 #include  #include  #include  void ** array2d(size_t rows, size_t cols, size_t value_size) { size_t index_size = sizeof(void *) * rows; size_t store_size = value_size * rows * cols; char * a = malloc(index_size + store_size); if(!a) return NULL; memset(a + index_size, 0, store_size); for(size_t i = 0; i < rows; ++i) ((void **)a)[i] = a + index_size + i * cols * value_size; return (void **)a; } int printf(const char *, ...); int main() { int ** a = (int **)array2d(5, 5, sizeof(int)); assert(a); a[4][3] = 42; printf("%i\n", a[4][3]); free(a); return 0; } 

No estoy seguro de si es realmente seguro emitir el void ** a int ** (creo que el estándar permite que las conversiones se realicen al convertir a / desde el void * ?), Pero funciona en gcc. Para estar seguro, debe reemplazar cada ocurrencia de void * con int * ...


Las siguientes macros implementan una versión de tipo seguro del algoritmo anterior:

 #define alloc_array2d(TYPE, ROWS, COLS) \ calloc(sizeof(TYPE *) * ROWS + sizeof(TYPE) * ROWS * COLS, 1) #define init_array2d(ARRAY, TYPE, ROWS, COLS) \ do { for(int i = 0; i < ROWS; ++i) \ ARRAY[i] = (TYPE *)(((char *)ARRAY) + sizeof(TYPE *) * ROWS + \ i * COLS * sizeof(TYPE)); } while(0) 

Úselos así:

 int ** a = alloc_array2d(int, 5, 5); init_array2d(a, int, 5, 5); a[4][3] = 42; 

Aunque estoy de acuerdo con las otras respuestas, en la mayoría de los casos es mejor asignar todo el conjunto de una vez, porque malloc es bastante lento.

 int ** array_new(size_t rows, size_t cols) { int **array2d, **end, **cur; int *array; cur = array2d = malloc(rows * sizeof(int *)); if (!array2d) return NULL; array = malloc(rows * cols * sizeof(int)); if (!array) { free(array2d); return NULL; } end = array2d + rows; while (cur != end) { *cur = array; array += cols; cur++; } return array2d; } 

Para liberar la matriz, simplemente haz: free(*array); free(array); free(*array); free(array);

Nota: esta solución solo funciona si no desea cambiar el orden de las filas, ya que podría perder la dirección del primer elemento, lo que necesita para liberar la matriz más tarde.

Humm. ¿Qué tal el humo y los espejos a la antigua como una opción?

 #define ROWS 5 #define COLS 13 #define X(R, C) *(p + ((R) * ROWS) + (C)) int main(void) { int *p = (int *) malloc (ROWS * COLS * sizeof(int)); if (p != NULL) { size_t r; size_t c; for (r = 0; r < ROWS; r++) { for (c = 0; c < COLS; c++) { X(r,c) = r * c; /* put some silly value in that position */ } } /* Then show the contents of the array */ for (r = 0; r < ROWS; r++) { printf("%d ", r); /* Show the row number */ for (c = 0; c < COLS; c++) { printf("%d", X(r,c)); } printf("\n"); } free(p); } else { /* issue some silly error message */ } return 0; } 

El uso de malloc(3) para asignar la primera matriz y poner allí punteros creados por malloc(3) debería funcionar con la array[r][c] porque debería ser equivalente a *(*(array + r) + c) , está en el estándar C