2010-04-15 8 views
8

¿Por qué el siguiente código da como resultado un error de segmentación? (Estoy intentando crear dos matrices del mismo tamaño, uno con estática y el otro con la asignación dinámica)Asignación de memoria para una matriz en C

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

//Segmentation fault! 
int main(){ 
    #define X 5000 
    #define Y 6000 

    int i; 
    int a[X][Y]; 

    int** b = (int**) malloc(sizeof(int*) * X); 
    for(i=0; i<X; i++){ 
     b[i] = malloc (sizeof(int) * Y); 
    } 
} 

Extrañamente, si comento hacia fuera una de las definiciones de la matriz, el código se ejecuta correctamente. De esta manera:

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

//No Segmentation fault! 
int main(){ 
    #define X 5000 
    #define Y 6000 

    int i; 
    //int a[X][Y]; 

    int** b = (int**) malloc(sizeof(int*) * X); 
    for(i=0; i<X; i++){ 
     b[i] = malloc (sizeof(int) * Y); 
    } 
} 

o

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

//No Segmentation fault! 
int main(){ 
    #define X 5000 
    #define Y 6000 

    int i; 
    int a[X][Y]; 

    //int** b = (int**) malloc(sizeof(int*) * X); 
    //for(i=0; i<X; i++){ 
    // b[i] = malloc (sizeof(int) * Y); 
    //} 
} 

estoy corriendo gcc en Linux en una máquina de 32 bits.

Editar: Verificando si malloc() tiene éxito:

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

//No Segmentation fault! 
int main(){ 
    #define X 5000 
    #define Y 6000 

    int i; 
    int a[X][Y]; 

    int* tmp; 
    int** b = (int**) malloc(sizeof(int*) * X); 
    if(!b){ 
     printf("Error on first malloc.\n"); 
    } 
    else{ 
     for(i=0; i<X; i++){   
      tmp = malloc (sizeof(int) * Y); 
      if(tmp) 
       b[i] = tmp; 
      else{ 
       printf("Error on second malloc, i=%d.\n", i); 
       return; 
      } 
     } 
    }  
} 

No se imprime nada cuando lo ejecuto (esperar, por supuesto, de "Fallo de segmentación")

+0

Pruebe 'fprintf' a' stderr'. 'printf' se imprime a' stdout', que está almacenado en el búfer, por lo que si el programa falla, es probable que pierda el resultado. –

+0

¿También puede imprimir i y ver qué tan avanzado está antes de fallar? –

Respuesta

2

Se produce un error de segmentación, lo que significa que su programa está intentando acceder a una dirección de memoria que no ha sido asignada a su proceso. La matriz a es una variable local y, por lo tanto, memoria asignada de la pila. Como unwind señaló a requiere 120 Mbytes de almacenamiento. Esto es casi seguramente más grande que el espacio de pila que el sistema operativo ha asignado a su proceso. Tan pronto como el bucle for se aleja del final de la pila, se produce un error de segmentación.

En Linux el tamaño de pila es controlado por el sistema operativo no el compilador así que pruebe lo siguiente: -

$ ulimit -a 

En la respuesta debería ver una línea como la siguiente: -

stack size (kbytes)   (-s) 10240 

Esto significa que cada proceso obtiene 10Mbyte de almacenamiento, ni mucho menos para su gran matriz.

Puede ajustar el tamaño de la pila con un comando ulimit -s <stack size>, pero sospecho que no le permitirá seleccionar un tamaño de pila de 120 MB.

La solución más simple es hacer que a sea una variable global en lugar de una variable local.

+0

Hacer 'a' una variable global de hecho hizo el truco. ¡Gracias! (El programa real en el que estoy trabajando es en realidad mucho más complejo que este ejemplo de juguete, pero se aplica el mismo principio, así que creo que ahora puedo volver a él). – Snogzvwtr

1

Esas son las asignaciones de tamaño considerable. ¿Ha intentado verificar para asegurarse de que malloc() tiene éxito?

Puede usar malloc() para todas sus matrices y comprobar para asegurarse de que tenga éxito cada vez.

6

Su variable a requiere, en un sistema de 32 bits, 5000 * 6000 * 4 = 120 MB de espacio de pila. Es posible que esto viole algún límite, lo que causa la falla de segmentación.

Además, es posible que malloc() falle en algún momento, lo que puede provocarle la eliminación de un puntero NULL.

+0

Pensé en eso, pero todavía no puedo entender que el tercer código funcione si ese es el caso. De todos modos, traté de verificar los resultados de malloc(), aparentemente todos están teniendo éxito. – Snogzvwtr

0

Su tercer código tampoco funciona (en mi sistema al menos).

Intente asignar memoria a la matriz a en el montón (cuando las dimensiones son grandes).

2

tratar de aumentar los límites del montón y pila de GCC:

gcc -Wl,--stack=xxxxx -Wl,--heap=yyyyy 
+0

Intentó, pero obtuvo una "opción no reconocida" --stack '". Por lo que comprobé, al parecer, esas opciones son solo para Windows. Estoy en Linux. – Snogzvwtr

+0

En realidad, en Linux, estas opciones están disponibles solo para objetivos PE i386. – Juliano

0

Ambas matrices no caben en los límites de su memoria. Puede asignar solo uno a la vez.

Si define Y como 3000 en vez de 6000, su programa no debería emitir segfault.

+0

Tengo (mucho) más de 120 MB de memoria disponible. Debe haber una forma de hacerlo bien. (En realidad, las matrices que necesitaré en mi programa actual son aún mayores, esto es solo un ejemplo de juguete para ayudar a descubrir qué está pasando mal). – Snogzvwtr

1

Un desbordamiento de la pila (¡qué apropiado!) Puede provocar un error de segmentación, que es lo que parece que está viendo aquí.

En su tercer caso, el puntero de pila se mueve a una dirección no válida pero no se usa para nada, ya que el programa se cierra. Si pone cualquier operación después de la asignación de la pila, debería obtener una segfault.

1

Quizás el compilador simplemente está cambiando el puntero de la pila a un valor grande pero nunca lo usa, y por lo tanto nunca causa una violación de acceso a la memoria.

Intente inicializar todos los elementos de A en su tercer ejemplo? Su primer ejemplo intenta asignar B después de A en la pila, y acceder a la pila tan alta (en la primera asignación a B) podría ser lo que está causando la segfault.

+0

Gracias, creo que ahora entiendo el problema. No me había dado cuenta antes de que procesar la pila (para crear b) * después de * asignar ese espacio a a es lo que podría causar la segfault. – Snogzvwtr

Cuestiones relacionadas