Warum stürzt dieses Programm ab?



  • Undefiniertes Verhalten schrieb:

    Okay, aber wenn man nun dringend ein größeres Array braucht, wie wird das dann gelöst?

    Dann geht es nicht. Irgendwann ist Schluß.

    Oder mehr Speicher reinbauen, anderen Rechner nehmen.
    Du kannst dir auch eine andere Speicherstrategie ausdenken.
    Muss es ein Array sein? (ein großer Speicherbereich)
    Oder geht auch eine Liste oder ein Array mit Zeigern auf Arrays? (viele kleine Bereiche)



  • DirkB schrieb:

    Undefiniertes Verhalten schrieb:

    Okay, aber wenn man nun dringend ein größeres Array braucht, wie wird das dann gelöst?

    Dann geht es nicht. Irgendwann ist Schluß.

    Oder mehr Speicher reinbauen, anderen Rechner nehmen.

    Wenn der Speicher also fragmentiert ist, dann hilft nur noch mehr physikalisches RAM oder eine andere Datenstruktur, habe ich das so richtig verstanden?

    Falls ja, wie soll ich dann wissen, auf welchen kleinsten gemeinsammen Nenner ich mich immer verlassen kann?

    Auf dem Computer könnten ja > 10 Mio Prozesse laufen, so daß der Speicher völlig fragmentiert ist.
    Dann würde ich nichtmal kleine zusammenhängende Speicherbereiche finden, solange es keinen Weg gibt, das OS dazu zu zwingen, den Speicher zu defragmentieren.

    Muss es ein Array sein? (ein großer Speicherbereich)
    Oder geht auch eine Liste oder ein Array mit Zeigern auf Arrays? (viele kleine Bereiche)

    Momentan ist es nur eine rein akademische Frage, für den Fall das ich mal einen großen Zusammenhängenden Speicherbereich als Array benötige.

    Ein Array in mehrere Arrays zerstückeln würde natürlich, wenn es nicht anders geht und es mal notwendig sein sollte, natürlich schon gehen, da ist dann halt etwas Aufwand.

    Aber ich habe nochmal eine Frage zu malloc, ich habe jetzt versucht im zweiten Quelltext malloc zu verwenden, aber ich erhalte Fehlermeldungen beim compilieren:

    #include <stdio.h>
    #include <limits.h>
    #include <stdlib.h>
    
    // Wenn Programm abstuerzen soll, dann ABSTURZ auf 1 setzen
    #define ABSTURZ 1
    
    #define DYNAMISCH 1
    
    #if (ABSTURZ)
    #  if (DYNAMISCH)
    #    define ELEMENTE 520612
    #  else
    #    define ELEMENTE 520612
    #  endif
    #else
    #  define ELEMENTE 520611
    #endif
    
    int main(){
      int size = 0;
    
      if (DYNAMISCH){
        int *i = malloc(ELEMENTE * sizeof(*i));
      } else {
        int i[ELEMENTE];
      }
      i[2] = 42;
      size = sizeof(size);
      printf("Ein int Wert belegt auf dieser Maschine %i Bytes.\n\n", size);
      printf("Das Array i enthaelt %i Elemente.\n\n", sizeof(i)/size);
      printf("Es wurden %i KByte belegt.\n", sizeof(i)/1024);
    
      if (DYNAMISCH){
          free(i);
      }
      return 0;
    }
    

    gcc -std=c99 -Wall -o "riesenarray" "riesenarray.c" (im Verzeichnis: D:\prog)
    riesenarray.c: In function 'main':
    riesenarray.c:27:9: warning: unused variable 'i'
    riesenarray.c:29:3: error: 'i' undeclared (first use in this function)
    riesenarray.c:29:3: note: each undeclared identifier is reported only once for each function it appears in
    Kompilierung fehlgeschlagen.

    27:9 ist klar, aber 29:3 nicht.
    Ich habe doch jetzt einen Zeiger Namens *i, der auf einen Speicherbereich zeigt, der mit malloc reserviert wurde.



  • Habe gerade die Antwort gefunden, das bei malloc ein sizeof nichts mehr bringt:

    http://www.c-faq.com/malloc/querysize.html



  • Die Variable i (egal ob Zeiger oder Array) ist nur innerhalb des Scopes (den Umgebnden geschweiften Klammern) definiert.
    Nach dem if gibt es die Variablen nicht mehr.
    Mach das mit dem Preprozessor (#if #else #endif)

    Auf modernen Betriebssystemen bekommt jeder Prozess dank der MMU einen komplett eigenen zusammenhängenden Speicherbereich. Wenn der reale Speicher belegt ist, wird geswapt.



  • DirkB schrieb:

    Die Variable i (egal ob Zeiger oder Array) ist nur innerhalb des Scopes (den Umgebnden geschweiften Klammern) definiert.
    Nach dem if gibt es die Variablen nicht mehr.
    Mach das mit dem Preprozessor (#if #else #endif)

    Danke, ich habe es jetzt so umgebaut.
    (Mache zum Testen halt jetzt zwei Arrays, aber da sizeof nicht bei malloc geht, wäre es auch nicht anders sinnvoll gewesen)

    #include <stdio.h>
    #include <limits.h>
    #include <stdlib.h>
    
    // Wenn Programm abstuerzen soll, dann ABSTURZ auf 1 setzen
    #define ABSTURZ 1
    
    #if (ABSTURZ)
    #  define ELEMENTE 520612
    #else
    #  define ELEMENTE 520611
    #endif
    
    int main(){
      int size = 0;
      int *i_dyn = malloc(ELEMENTE * sizeof(*i_dyn));
    
      if (!(i_dyn == NULL)){
        printf("Speicher konnte reserviert werden.\n");
      }
      else {
        printf("Speicherreservierung war nicht erfolgreich.\n");
      }
    
      #ifdef ABSTURZ
        int i[ELEMENTE - 1];
      #else
        int i[ELEMENTE];
      #endif
      i[2] = 42;
      size = sizeof(size);
      printf("Ein int Wert belegt auf dieser Maschine %i Bytes.\n\n", size);
      printf("Das Array i enthaelt %i Elemente.\n\n", sizeof((void*)i)/size);
      printf("Es wurden %i KByte belegt.\n", sizeof(i)/1024);
    
      if (i_dyn){
        free(i_dyn);
      }
      return 0;
    }
    

    Dummerweise stürzt er jetzt immer noch ab, obwohl i jetzt nicht die maximale Elementanzahl, die zum Absturz führt, erreichen sollte.

    Auf modernen Betriebssystemen bekommt jeder Prozess dank der MMU einen komplett eigenen zusammenhängenden Speicherbereich. Wenn der reale Speicher belegt ist, wird geswapt.

    Danke, dann muss ich mir um die physikalische Fragementierung also gar keine Sorgen machen, richtig?

    Wenn also genug Speicher frei ist, dann kriege ich auch genug Speicher am Stück. Also für den Prozess am Stück.



  • Ich denke ich weiß jetzt warum es nun dennoch abstürzt.

    Diese 2033 KByte beziehen sich auf alle Datenwerte.

    Da ich nun einen 4 Byte großen Pointer (32 Bit Programm) Namens i_dyn erstelle,
    muss ich in Zeile 28 die Anzahl der ELEMENTE nicht um 1, sondern um 2 abziehen.

    Also so:

    int i[ELEMENTE - 2]

    dann geht es wieder.

    Mein normales VLA i ist dann allerdings auch um 4 Byte bzw. 1 Element kleiner, also genau der Platz, den der zusätzliche Pointer belegt.

    So sieht mein Code aktuell aus:

    #include <stdio.h>
    #include <limits.h>
    #include <stdlib.h>
    
    // Wenn Programm abstuerzen soll, dann ABSTURZ auf 1 setzen
    #define ABSTURZ 1
    
    #if (ABSTURZ)
    #  define ELEMENTE 520612
    #else
    #  define ELEMENTE 520611
    #endif
    
    int main(){
      int size = 0;
      int *i_dyn = malloc(ELEMENTE * sizeof(*i_dyn));
    
      if (!(i_dyn == NULL)){
        printf("Speicher konnte reserviert werden.\n");
      }
      else {
        printf("Speicherreservierung war nicht erfolgreich.\n");
      }
    
      #if (ABSTURZ)
        int i[ELEMENTE - 2];
      #else
        int i[ELEMENTE];
      #endif
    
      i[2] = 42;
      size = sizeof(size);
      printf("Ein int Wert belegt auf dieser Maschine %i Bytes.\n\n", size);
      printf("Das Array i enthaelt %i Elemente.\n\n", sizeof(i)/size);
      printf("Es wurden %i KByte belegt.\n", sizeof(i)/1024);
    
      if (i_dyn){
        free(i_dyn);
      }
      return 0;
    }
    


  • Zeile 30 muss ich dann allerdings auch auf

    int i[ELEMENTE - 1] ändern.

    Und je mehr zusätzliche Variablen ich definiere, desto mehr muss ich von ELEMENTE abziehen um mein VLA i zu erstellen.

    Oder anders gesagt, es sind maximal nur "ELEMENTE+1" einwertige Variablen (also ohne Arrays) möglich.
    In diesem Fall also 520613, mehr Variablen können nicht definiert werden.



  • Die Unterscheidung ab Zeile 27 ist Blödsinn, da du das ja schon ab Zeile 8 regelst.

    Du kannst auch durch Compiler/Linkeroptionen die Stackgröße ändern.



  • DirkB schrieb:

    Die Unterscheidung ab Zeile 27 ist Blödsinn, da du das ja schon ab Zeile 8 regelst.

    Nein ist sie nicht.

    Weil ich hier keinen Absturz mehr haben wollte, es sollte lediglich berücksichtigt werden, das das größere Array per malloc erzeugt werden kann, aber das int[] Array nicht zum Absturz führt.

    Deswegen steht da ja auch in Zeile 28 ELEMENTE - 2

    Du kannst auch durch Compiler/Linkeroptionen die Stackgröße ändern.

    Wie lautet der Kommandozeilenparameter dazu?



  • Undefiniertes Verhalten schrieb:

    DirkB schrieb:

    Du kannst auch durch Compiler/Linkeroptionen die Stackgröße ändern.

    Wie lautet der Kommandozeilenparameter dazu?

    MinGW-gcc: -Wl,--stack,10000000 reserviert 10 MB Stack zu Programmbeginn.

    viele grüße
    ralph


Anmelden zum Antworten