2010-04-15 11 views
8

Warum führt der folgende Code zum Fehler Segmentation? (Ich versuche, zwei Matrizen der gleichen Größe zu erstellen, eine mit statischen und das andere mit der dynamischen Zuordnung)Speicherzuordnung für eine Matrix in 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); 
    } 
} 

Seltsam genug, wenn ich eine der Matrix Definitionen Kommentar aus, wird der Code in Ordnung. Wie folgt aus:

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

oder

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

Ich bin mit gcc unter Linux auf einer 32-Bit-Maschine.

Edit: zu überprüfen, ob malloc() erfolgreich:

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

Nichts wird gedruckt, wenn ich es laufen (erwarten natürlich für "Segmentation fault")

+0

Versuchen Sie 'fprintf' zu' stderr'. 'printf' druckt auf' stdout', was gepuffert ist. Wenn das Programm abstürzt, werden Sie wahrscheinlich die Ausgabe verlieren. –

+0

Kannst du auch ausdrucken und sehen, wie weit es in der Schleife geht, bevor es scheitert? –

Antwort

2

Sie erhalten einen Segmentierungsfehler, was bedeutet, dass Ihr Programm versucht, auf eine Speicheradresse zuzugreifen, die seinem Prozess nicht zugewiesen wurde. Das Array a ist eine lokale Variable und weist somit Speicher aus dem Stack zu. Wie unwind wies darauf hin, a erfordert 120 MB Speicher. Dies ist fast sicher größer als der Stack-Speicher, den das Betriebssystem Ihrem Prozess zugewiesen hat. Sobald die for-Schleife das Ende des Stapels erreicht, erhalten Sie einen Segmentierungsfehler.

In Linux die Stack-Größe vom Betriebssystem gesteuert wird, nicht der Compiler versuchen so die folgende: -

$ ulimit -a 

In der Antwort sollten Sie eine Zeile wie diese sehen: -

stack size (kbytes)   (-s) 10240 

Das bedeutet, dass jeder Prozess 10 MByte Speicherplatz erhält, der für Ihr großes Array nicht annähernd ausreicht.

Sie können die Stapelgröße mit einem ulimit -s <stack size> Befehl anpassen, aber ich vermute, dass Sie nicht eine 120Mbyte Stapelgröße auswählen können!

Die einfachste Lösung ist a eine globale Variable anstelle einer lokalen Variablen zu machen.

+0

Es hat tatsächlich eine 'globale' Variable gemacht. Vielen Dank! (Das eigentliche Programm, an dem ich gerade arbeite, ist viel komplexer als dieses Spielzeugbeispiel, aber es gilt das gleiche Prinzip, also denke ich, dass ich jetzt zurückgehen kann). – Snogzvwtr

1

Das sind beträchtliche Zuweisungen. Haben Sie versucht, sicherzustellen, dass malloc() erfolgreich ist?

Sie könnten malloc() für alle Ihre Arrays verwenden und sicherstellen, dass es jedes Mal erfolgreich ist.

6

Ihre Variable a erfordert auf einem 32-Bit-System 5000 * 6000 * 4 = 120 MB Stapelspeicher. Es ist möglich, dass dies einen Grenzwert verletzt, der den Segmentierungsfehler verursacht.

Es ist natürlich auch möglich, dass malloc() an einem bestimmten Punkt fehlschlägt, was dazu führen könnte, dass Sie einen NULL Zeiger dereferenzieren.

+0

ich zwar davon, aber ich kann immer noch nicht mit dem dritten Code funktioniert, wenn das der Fall ist. Wie auch immer, ich habe versucht, auf malloc() Ergebnisse zu überprüfen, anscheinend sind sie alle erfolgreich. – Snogzvwtr

0

Ihr 3. Code funktioniert auch nicht (zumindest auf meinem System).

Versuchen Sie, Speicher auf Array a auf dem Haufen eher zuzuweisen (wenn Dimensionen groß sind).

2

Try Heap und Stack Grenzen in GCC zu erhöhen:

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

Versucht, aber eine "nicht erkannte Option '--stack'". Von dem, was ich überprüft habe, sind diese Optionen anscheinend nur für Windows. Ich bin auf Linux. – Snogzvwtr

+0

Diese Optionen sind unter Linux nur für i386 PE-Ziele verfügbar. – Juliano

0

Beide Matrizen in den Grenzen der Speicher nicht passen. Sie können jeweils nur einen zuweisen.

Wenn Sie Y als 3000 statt als 6000 definieren, sollte Ihr Programm keinen segfault ausgeben.

+0

Ich habe (viel) mehr als 120 MB verfügbaren Speicher. Es muss einen Weg geben, dies richtig zu machen. (Eigentlich sind die Matrizen, die ich für mein aktuelles Programm benötige, sogar noch größer - das ist nur ein Spielzeugbeispiel, um herauszufinden, was schief läuft.) – Snogzvwtr

1

Ein Stack-Überlauf (wie geeignet!) Kann zu einem Segmentierungsfehler führen, den Sie hier zu sehen scheinen.

In Ihrem dritten Fall wird der Stapelzeiger an eine ungültige Adresse verschoben, wird aber für nichts mehr verwendet, da das Programm dann beendet wird. Wenn Sie eine Operation nach der Stapelzuordnung einfügen, sollten Sie einen segfault erhalten.

1

Vielleicht ändert der Compiler nur den Stapelzeiger auf einen großen Wert, verwendet ihn aber nie und verursacht daher niemals eine Speicherzugriffsverletzung.

Versuchen Sie, alle Elemente von A in Ihrem dritten Beispiel zu initialisieren? Ihr erstes Beispiel versucht, B nach A auf dem Stack zuzuweisen und auf den Stack zuzugreifen, der auf der ersten Zuweisung zu B den Wert "high" hat.

+0

Danke, ich denke jetzt verstehe ich das Problem. Ich habe vorher nicht bemerkt, dass das Eingeben des Stapels (um b zu erzeugen) * nachdem * soviel Platz zu a zugewiesen wurde, was den segfault verursachen könnte. – Snogzvwtr