Warum stürzt dieses Programm ab, wenn man Speicher für mehr als 5 int Werte reserviert?
-
Bei folgendem Code wird jeweils zweimal dynamisch Speicher angefordert.
Beim ersten mal, wird der Speicher quasi als gewöhnliches Array an einen Pointer übergeben.
Beim zweiten mal, wird der Speicher an ein Struct übergeben und dort mitsamt der Länge gespeichert.Das Problem ist nun.
Klammert man einen der beiden Fälle aus, dann funktioniert das Programm ohne abzustürzen. Sobald aber beide Varianten gleichzeitig im Code aktiv und ausgeführt werden, hängt es ganz davon ab, was man als Benutzer eingibt.
Bei Zahlen größer 5, z.B. bei Eingabe einer 6 oder 10, stürzt es dann in der Regel ab.Wieso?
#include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> // C99 struct dyn_array{ unsigned long long int length; int *ptr; }; long int eingabe(){ char line[100]; unsigned long long int input; do { fgets(line,sizeof(line),stdin); } while(1 != sscanf(line,"%llu",&input)); return input; } int main(){ unsigned long long int i; printf("Für wie viele int Werte wollen sie Speicher reservieren? "); i = eingabe(); printf("Antwort: Für %llu\n", i); /* ********************** Variante 1 ************************ */ int *pointer = malloc(i * sizeof (int)); /* Wir nutzen mal unser dynamisches Array, damit es der Compiler nicht wegrationalisiert */ for (unsigned long long int k = 0; k <= i; k++){ pointer[k] = (int) k; } // Wir geben es aus, damit es nicht wegrationalisiert wird. printf("An Stelle 0 enthält das int Array den Wert %i.\n\n", pointer[0]); /* ********************** Variante 2 ************************ */ struct dyn_array feld; feld.ptr = malloc(i * sizeof(*feld.ptr)); // feld.ptr = malloc(i * sizeof(int)); feld.length = i; /* Wir nutzen mal unser dynamisches Array, damit es der Compiler nicht wegrationalisiert */ for (unsigned long long int k = 0; k <= feld.length; k++){ feld.ptr[k] = (int) k; } // und geben aus dem selben Grund einen Wert aus, damit es nicht wegrationalisiert wird. printf("An Stelle 0 enthält das int Array, auf das in unserem Struct verwiesen wird,\n" "den Wert %i und die Länge beträgt %llu.\n\n", feld.ptr[0], feld.length); free(pointer); free(feld.ptr); return 0; }
./struct.bin Für wie viele int Werte wollen sie Speicher reservieren? 6 Antwort: Für 6 An Stelle 0 enthält das int Array den Wert 0. struct.bin: malloc.c:2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' failed. Abgebrochen (Speicherabzug geschrieben)
-
Du schreibst einen Wert mehr in deine Felder als Platz dafür ist.
-
Oh ja, da sucht man wie verrückt und übersieht dann das offensichtliche.
Da habe ich ehrlich gar nicht mehr nachgeguckt, weil ich dachte, ich hätte das schon richtig gemacht.
Danke für den Hinweis.
-
Hat zwar mit deiner Frage nix zu tun (die hat ja SeppJ schon beantwortet), aber:
/* Wir nutzen mal unser dynamisches Array, damit es der Compiler nicht wegrationalisiert */
Der Compiler kann
malloc
Aufrufe normalerweise nicht wegoptimieren.
Vermutlich könnte er es können, aber können tut er's trotzdem nicht (behaupte ich jetzt mal einfach so)
Weil ermalloc
einfach nur als ihm unbekannte Funktion ansieht, die Nebeneffekte haben könnte. Und damit beobachtbar ist. Und damit drin bleiben muss.
-
hustbaer schrieb:
Weil er
malloc
einfach nur als ihm unbekannte Funktion ansieht, die Nebeneffekte haben könnte. Und damit beobachtbar ist. Und damit drin bleiben muss.Bei Funktionen der Standardbibliothek darf er das durchaus optimieren. Da ist es, wenn ich mich recht entsinne, undefiniertes Verhalten, wenn man versucht, eine eigene Funktion mit gleichem Namen zu definieren. Daher darf angenommen werden, dass soclhe Funktionen tatsächlich das tun, was im Standard steht. In der Folge dürfen sie daher direkt durch Intrinsiks ersetzt oder sonstwie umgeformt werden. Ob das insbesondere bei malloc geschieht, kann ich in diesem speziellen Fall nicht sagen (ich sehe da kein großes Optimierungspotential), aber an anderen Stellen wird davon durchaus reichlich Gebrauch gemacht. Typische Beispiele, die ich bereits beobachtet habe, wären printf von Zeichenketten durch puts/fputs ersetzen oder Mathefunktionen zur Compilezeit berechnen.
-
Ist mir klar. (OK. Sagen wir: ich hatte es vermutet
)
Deswegen hab' ich ja geschrieben "vermutlich könnte er es können".
Ich hab' malloc Optimierungen einfach noch nie gesehen.
-
Wie kann ich feststellen, dass durch die Optimierung fprint() in puts() geändert wurde?
Gibt es Compiler-Optionen, bei denen eine optimierte QUelldatei erstellt wird oder muss ich den kompilierten dekompilieren um diese Optimierungen zu sehen?
-
.keen schrieb:
Gibt es Compiler-Optionen, bei denen eine optimierte QUelldatei erstellt wird
Sollte es bei den meisten Compilern geben. Beim GCC beispielsweise mittels des Schalters -S (oder war es -s? Vergess ich immer und bin gerade zu faul, zu gucken).
oder muss ich den kompilierten dekompilieren um diese Optimierungen zu sehen?
Decompilieren wird da vermutlich nicht viel bringen. Dir ist schon klar, dass die Optimierungen seitens des Compilers nicht auf Ebene des Quellcodes passieren? Die oben erwähnte Ausgabe des optimierten Codes ist das Endresultat, also in Assembler. Aber dass da plötzlich
call puts
stattcall printf
steht, kann man selbst ganz ohne Assemblerkenntnisse nachvollziehen.
-
SeppJ schrieb:
.keen schrieb:
Gibt es Compiler-Optionen, bei denen eine optimierte QUelldatei erstellt wird
Sollte es bei den meisten Compilern geben. Beim GCC beispielsweise mittels des Schalters -S (oder war es -s? Vergess ich immer und bin gerade zu faul, zu gucken).
Ein großes -S ergibt den Assemblercode, ein kleines -s ergibt ein stripped binary.