Error de segmentación de error en la asignación de memoria de matriz 3D

Tengo una variable de puntero int ***a en C. Lo estoy pasando a una función como &a ie referencia. En la función estoy obteniendo una variable de puntero de tipo int ****a . Estoy asignando memoria como esta.

 *a=(int***)malloc(no1*sizeof(int**)); some loop from 0 to no1 (*a)[++l]=(int**)malloc((no1+1)*sizeof(int*)); some loop from 0 to no1 (*a)[l][h]=(int*)malloc(2*sizeof(int)); 

Este es sólo el tiempo que asigné memoria. El progtwig actual no está dado; no hay error aquí Pero cuando voy a hacer esto:

 (*a)[l][h][0]=no1; 

Me está dando un error de “Falla de segmentación” y no puedo entender por qué.

ACTUALIZACIÓN: He escrito un progtwig de muestra que es para asignar la memoria solamente. Esto también está dando error de “falla de segmentación”.

 #include #include #include void allocate(int ****a) { int i,j,k; if(((*a)=(int***)malloc(5*sizeof(int**)))==NULL) { printf("\nError in allocation of double pointer array\n"); exit(0); } for(i=0;i<5;i++)if(((*a)[i]=(int**)malloc(4*sizeof(int*)))==NULL) { printf("\nError in allocation of single pointer array on index [%d]\n",i); exit(0); } for(i=0;i<5;i++) for(j=0;j<4;i++) if(((*a)[i][j]=(int*)malloc(3*sizeof(int)))==NULL) { printf("\nError in allocation of array on index [%d][%d]\n",i,j); exit(0); } for(i=0;i<5;i++) for(j=0;j<4;i++) for(k=0;k<3;k++) (*a)[i][j][k]=k; } main() { int ***a; int i,j,k; allocate(&a); for(i=0;i<5;i++) for(j=0;j<4;i++) for(k=0;k<3;k++) printf("\na[%d][%d][%d] = %d ",i,j,k,a[i][j][k]); } 

Código revisado de la pregunta

Su código tiene:

 for(i=0;i<5;i++) for(j=0;j<4;i++) 

varias veces. El segundo bucle debería estar incrementando j, no i. Ten mucho cuidado con el copy'n'paste.

Este código no se bloquea (pero tiene fugas).

 #include  #include  void allocate(int ****a); void allocate(int ****a) { int i,j,k; printf("allocate: 1B\n"); if(((*a)=(int***)malloc(5*sizeof(int**)))==NULL) { printf("\nError in allocation of double pointer array\n"); exit(0); } printf("allocate: 1A\n"); printf("allocate: 2B\n"); for(i=0;i<5;i++) if(((*a)[i]=(int**)malloc(4*sizeof(int*)))==NULL) { printf("\nError in allocation of single pointer array on index [%d]\n",i); exit(0); } printf("allocate: 2A\n"); printf("allocate: 3B\n"); for(i=0;i<5;i++) for(j=0;j<4;j++) if(((*a)[i][j]=(int*)malloc(3*sizeof(int)))==NULL) { printf("\nError in allocation of array on index [%d][%d]\n",i,j); exit(0); } printf("allocate: 3A\n"); printf("allocate: 4B\n"); for(i=0;i<5;i++) for(j=0;j<4;j++) for(k=0;k<3;k++) (*a)[i][j][k]=k; printf("allocate: 4A\n"); } int main(void) { int ***a; int i,j,k; allocate(&a); for(i=0;i<5;i++) for(j=0;j<4;j++) for(k=0;k<3;k++) printf("a[%d][%d][%d] = %d\n",i,j,k,a[i][j][k]); } 

Respuestas anteriores

Ya que no nos ha mostrado la mayoría del código, es difícil predecir cómo lo está mal manejando, pero igualmente, ya que está obteniendo un volcado de memoria, debe estar manejando mal algo.

Este es un código de trabajo, que no se verifica con valgrind ya que no está disponible para Mac OS X 10.8, que parece funcionar. La recuperación de errores por error de asignación no está completa, y también falta la función para destruir la matriz totalmente asignada.

 #include  #include  #include  static int ***allocate_3d_array(int no1, int ****a) { *a = (int***)malloc(no1 * sizeof(int**)); if (*a == 0) return 0; for (int l = 0; l < no1; l++) { if (((*a)[l]=(int**)malloc((no1+1)*sizeof(int*))) == 0) { while (l > 0) free((*a)[--l]); return 0; } } for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) { if (((*a)[l][h]=(int*)malloc(2*sizeof(int))) == 0) { /* Leak! */ return 0; } } } for (int l = 0; l < no1; l++) for (int h = 0; h < no1; h++) for (int k = 0; k < 2; k++) (*a)[l][h][k] = 10000 * l + 100 * h + k; return *a; } int main(void) { int no1 = 5; int ***a = 0; int ***b = allocate_3d_array(no1, &a); const char *pad[] = { " ", "\n" }; assert(b == a); if (a != 0) { for (int l = 0; l < no1; l++) for (int h = 0; h < no1; h++) for (int k = 0; k < 2; k++) printf("a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]); // free memory - added by harpun; reformatted by Jonathan Leffler // Would be a function normally — see version 2 code. for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) free(a[l][h]); free(a[l]); } free(a); } return 0; } 

Salida de muestra:

 a[0][0][0] = 000000 a[0][0][1] = 000001 a[0][1][0] = 000100 a[0][1][1] = 000101 a[0][2][0] = 000200 a[0][2][1] = 000201 a[0][3][0] = 000300 a[0][3][1] = 000301 a[0][4][0] = 000400 a[0][4][1] = 000401 a[1][0][0] = 010000 a[1][0][1] = 010001 a[1][1][0] = 010100 a[1][1][1] = 010101 a[1][2][0] = 010200 a[1][2][1] = 010201 a[1][3][0] = 010300 a[1][3][1] = 010301 a[1][4][0] = 010400 a[1][4][1] = 010401 a[2][0][0] = 020000 a[2][0][1] = 020001 a[2][1][0] = 020100 a[2][1][1] = 020101 a[2][2][0] = 020200 a[2][2][1] = 020201 a[2][3][0] = 020300 a[2][3][1] = 020301 a[2][4][0] = 020400 a[2][4][1] = 020401 a[3][0][0] = 030000 a[3][0][1] = 030001 a[3][1][0] = 030100 a[3][1][1] = 030101 a[3][2][0] = 030200 a[3][2][1] = 030201 a[3][3][0] = 030300 a[3][3][1] = 030301 a[3][4][0] = 030400 a[3][4][1] = 030401 a[4][0][0] = 040000 a[4][0][1] = 040001 a[4][1][0] = 040100 a[4][1][1] = 040101 a[4][2][0] = 040200 a[4][2][1] = 040201 a[4][3][0] = 040300 a[4][3][1] = 040301 a[4][4][0] = 040400 a[4][4][1] = 040401 

Compara esto con lo que tienes. Usted podría agregar muchos más mensajes de impresión de diagnóstico. Si esto no ayuda lo suficiente, cree un SSCCE (Ejemplo Corto, Autocontenido, Correcto ) análogo a este que demuestre el problema en su código sin ningún material extraño.

Versión 2 del código

Esta es una versión algo más compleja del código que simula fallas en la asignación de memoria después de N asignaciones (y un arnés de prueba que lo ejecuta con cada valor de N desde 0 hasta 35, donde en realidad hay solo 30 asignaciones para la matriz. incluye código para liberar la matriz (similar a, pero diferente de, el código que fue editado en mi respuesta por harpun . La interacción al final con la línea que contiene el PID significa que puedo verificar el uso de la memoria con ps en otra ventana de terminal). (De lo contrario, no me gustan los progtwigs que hacen ese tipo de cosas; supongo que debería ejecutar el ps desde mi progtwig a través del system() , pero me siento perezoso).

 #include  #include  #include  #include  static int fail_after = 0; static int num_allocs = 0; static void *xmalloc(size_t size) { if (fail_after > 0 && num_allocs++ >= fail_after) { fputs("Out of memory\n", stdout); return 0; } return malloc(size); } static int ***allocate_3d_array(int no1, int ****a) { *a = (int***)xmalloc(no1 * sizeof(int**)); if (*a == 0) return 0; for (int l = 0; l < no1; l++) { if (((*a)[l]=(int**)xmalloc((no1+1)*sizeof(int*))) == 0) { for (int l1 = 0; l1 < l; l1++) free((*a)[l1]); free(*a); *a = 0; return 0; } } for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) { if (((*a)[l][h]=(int*)xmalloc(2*sizeof(int))) == 0) { /* Release prior items in current row */ for (int h1 = 0; h1 < h; h1++) free((*a)[l][h1]); free((*a)[l]); /* Release items in prior rows */ for (int l1 = 0; l1 < l; l1++) { for (int h1 = 0; h1 < no1; h1++) free((*a)[l1][h1]); free((*a)[l1]); } free(*a); *a = 0; return 0; } } } for (int l = 0; l < no1; l++) for (int h = 0; h < no1; h++) for (int k = 0; k < 2; k++) (*a)[l][h][k] = 10000 * l + 100 * h + k; return *a; } static void destroy_3d_array(int no1, int ***a) { if (a != 0) { for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) free(a[l][h]); free(a[l]); } free(a); } } static void test_allocation(int no1) { int ***a = 0; int ***b = allocate_3d_array(no1, &a); const char *pad[] = { " ", "\n" }; assert(b == a); if (a != 0) { for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) { for (int k = 0; k < 2; k++) { if (a[l][h][k] != l * 10000 + h * 100 + k) printf("a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]); } } } } destroy_3d_array(no1, a); } int main(void) { int no1 = 5; for (fail_after = 0; fail_after < 33; fail_after++) { printf("Fail after: %d\n", fail_after); num_allocs = 0; test_allocation(no1); } printf("PID %d - waiting for some data to exit:", (int)getpid()); fflush(0); getchar(); return 0; } 

Tenga en cuenta lo dolorosa que es la recuperación de la memoria. Como antes, no se ha probado con valgrind , pero me tranquilizo con la prueba de Harpun en la versión anterior.

Versión 3 - Clean bill of health de valgrind

Este código es muy similar a la prueba en la versión 2. Corrige una pérdida de memoria en la limpieza cuando falla una asignación de memoria en las asignaciones de nivel hoja. El progtwig ya no solicita entradas (mucho preferible); toma un solo argumento opcional que es el número de asignaciones para fallar después. Las pruebas con valgrind mostraron que con un argumento 0-6, no hubo fugas, pero con el argumento 7 hubo una fuga. No tomó mucho tiempo para detectar el problema y solucionarlo. (Es más fácil cuando la máquina que ejecuta valgrind está disponible; se valgrind durante el fin de semana largo para la actualización del suministro eléctrico en el sitio general).

 #include  #include  #include  static int fail_after = 0; static int num_allocs = 0; static void *xmalloc(size_t size) { if (fail_after > 0 && num_allocs++ >= fail_after) { fputs("Out of memory\n", stdout); return 0; } return malloc(size); } static int ***allocate_3d_array(int no1, int ****a) { *a = (int***)xmalloc(no1 * sizeof(int**)); if (*a == 0) return 0; for (int l = 0; l < no1; l++) { if (((*a)[l]=(int**)xmalloc((no1+1)*sizeof(int*))) == 0) { for (int l1 = 0; l1 < l; l1++) free((*a)[l1]); free(*a); *a = 0; return 0; } } for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) { if (((*a)[l][h]=(int*)xmalloc(2*sizeof(int))) == 0) { /* Release prior items in current (partial) row */ for (int h1 = 0; h1 < h; h1++) free((*a)[l][h1]); /* Release items in prior (complete) rows */ for (int l1 = 0; l1 < l; l1++) { for (int h1 = 0; h1 < no1; h1++) free((*a)[l1][h1]); } /* Release entries in first (complete) level of array */ for (int l1 = 0; l1 < no1; l1++) free((*a)[l1]); free(*a); *a = 0; return 0; } } } for (int l = 0; l < no1; l++) for (int h = 0; h < no1; h++) for (int k = 0; k < 2; k++) (*a)[l][h][k] = 10000 * l + 100 * h + k; return *a; } static void destroy_3d_array(int no1, int ***a) { if (a != 0) { for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) free(a[l][h]); free(a[l]); } free(a); } } static void test_allocation(int no1) { int ***a = 0; int ***b = allocate_3d_array(no1, &a); const char *pad[] = { " ", "\n" }; assert(b == a); if (a != 0) { for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) { for (int k = 0; k < 2; k++) { if (a[l][h][k] != l * 10000 + h * 100 + k) printf("a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]); } } } } destroy_3d_array(no1, a); } int main(int argc, char **argv) { int no1 = 5; int fail_limit = 33; if (argc == 2) fail_limit = atoi(argv[1]); for (fail_after = 0; fail_after < fail_limit; fail_after++) { printf("Fail after: %d\n", fail_after); num_allocs = 0; test_allocation(no1); } return 0; } 

Versión 4 - Menos asignaciones de memoria

Actualización 2014-12-20

El código anterior hace muchas asignaciones de memoria, lo que complica la liberación y la recuperación de errores. Aquí hay una versión alternativa que hace solo 3 asignaciones, una para el vector de punteros a punteros, una para la matriz de punteros y otra para la matriz de enteros. A continuación, establece los punteros para señalar los lugares correctos en la memoria.

 #include  #include  #include  static int fail_after = 0; static int num_allocs = 0; static void *xmalloc(size_t size) { if (fail_after > 0 && num_allocs++ >= fail_after) { fputs("Out of memory\n", stdout); return 0; } return malloc(size); } static int ***allocate_3d_array(int no1, int ****a) { int ***d0 = (int***)xmalloc(no1 * sizeof(int**)); int **d1 = (int **)xmalloc(no1 * no1 * sizeof(int *)); int *d2 = (int *)xmalloc(no1 * no1 * 2 * sizeof(int)); if (d0 == 0 || d1 == 0 || d2 == 0) { free(d0); free(d1); free(d2); *a = 0; return 0; } for (int l = 0; l < no1; l++) { d0[l] = &d1[l * no1]; for (int h = 0; h < no1; h++) { d0[l][h] = &d2[(l * no1 + h) * 2]; for (int k = 0; k < 2; k++) d0[l][h][k] = l * 10000 + h * 100 + k; } } *a = d0; return *a; } static void destroy_3d_array(int ***a) { if (a != 0) { free(a[0][0]); free(a[0]); free(a); } } static void test_allocation(int no1) { int ***a = 0; int ***b = allocate_3d_array(no1, &a); const char *pad[] = { " ", "\n" }; assert(b == a); if (a != 0) { for (int l = 0; l < no1; l++) { for (int h = 0; h < no1; h++) { for (int k = 0; k < 2; k++) { if (a[l][h][k] != l * 10000 + h * 100 + k) printf("Oops: a[%d][%d][%d] = %.6d%s", l, h, k, a[l][h][k], pad[k]); } } } } destroy_3d_array(a); } int main(int argc, char **argv) { int no1 = 5; int fail_limit = 4; if (argc == 2) fail_limit = atoi(argv[1]); for (fail_after = 0; fail_after < fail_limit; fail_after++) { printf("Fail after: %d\n", fail_after); num_allocs = 0; test_allocation(no1); } return 0; } 

Esto tiene un buen estado de salud con GCC 4.9.1 en Mac OS X 10.10.1, verificado con la versión de valgrind valgrind-3.11.0.SVN (construido a partir de un árbol SVN con algunas correcciones necesarias para Mac OS X, pero no hay suficientes supresiones) ).

La impresión de diagnóstico (comenzando con 'Oops') se activó mientras desarrollaba la respuesta; Tuve mis cálculos de puntero mal en el momento.

Lo siento, pero, para ser franco: esta es una manera horrible de manejar una matriz 3D: un bucle de doble nested con un montón de llamadas a malloc() , luego triple indirección para obtener un valor en tiempo de ejecución. Yeuch : o)

La forma convencional de hacer esto (en la comunidad HPC) es usar una matriz unidimensional y hacer el cálculo del índice usted mismo. Supongamos que el índice i itera sobre nx planos en la dirección x , j itera sobre ny lápices en la dirección y , y k itera sobre nz celdas en la dirección z . Luego, un lápiz tiene nz elementos, un plano tiene nz*ny elementos, y todo el “ladrillo” tiene nz*ny*nx elementos. Por lo tanto, puede recorrer toda la estructura con:

 for(i=0; i 

La ventaja de esta construcción es que puede asignarlo con una sola llamada a malloc() , en lugar de un barco lleno de llamadas anidadas:

 int *a; a = malloc(nx*ny*nz*sizeof(int)); 

La construcción x=a[i][j][k] tiene tres niveles de direccionamiento indirecto: tiene que recuperar una dirección de la memoria, a , agregar un desplazamiento, i , recuperar esa dirección de la memoria, a[i] , agregar un offset, j , recupera esa dirección de la memoria, a[i][j] , agrega un offset, k , y (finalmente) recupera los datos, a[i][j][k] . Todos esos punteros intermedios están desperdiciando líneas de caché y entradas TLB.

La construcción x=a[(i*ny+j)*nz+k] tiene un nivel de direccionamiento indirecto a expensas de dos multiplicaciones de enteros adicionales: calcular el desplazamiento, buscar dirección, 'a', desde la memoria, calcular y agregar el desplazamiento, (i * ny + j) * nz + k, recupera los datos.

Además, esencialmente no hay forma de mejorar el rendimiento del método de triple direccionamiento basado en patrones de acceso a datos. Si realmente estuviéramos visitando cada celda, podríamos hacer algo como esto para evitar parte de la sobrecarga de cómputo del índice.

 ij = 0; for(i=0; i 

Dependiendo de lo que esté haciendo, esto tampoco puede ser bueno, y existen todos los diseños alternativos y métodos de indexación (como la indexación de Morton o Ahnenteufel) que pueden ser más adecuados, dependiendo de sus patrones de acceso. No estoy tratando de dar un tratado completo sobre la representación o indexación de la rejilla cartesiana 3D, simplemente ilustrar que una solución de "tres estrellas" es muy mala por varias razones.

Al utilizar (*a)[l][h][0] está intentando quitar la referencia a un int simple y no a un puntero.

use a[l][h][0] directamente para asignarle cualquier valor.