C Malloc und Realloc - es geht auch immer ohne (vorallem Realloc), Sinn der Sache?

ReVo

Lieutenant
Registriert
Jan. 2006
Beiträge
567
Hallo,

es ist schwer bei Malloc und Realloc zu prüfen ob alles richtig gemacht wurde oder nicht. Warum? Naja wenn ich einfach mal Speicher mit Malloc reserviere, sagen wir 5Byte aber ich 8Byte reinschreibe, dann gibt es kein Fehler. Weil das System automatisch das ganze erweitert. Hier habe ich 5Byte reserviert, ABER viel mehr reingeschrieben als nötig. Trozdem ist das kein Problem:

PHP:
	char *p;

	p = malloc(5); //irgendwo 5Byte Reservieren

	if(p != 0) 
		strcpy(p, "ABCDEFGHIJKL");
	else
		printf("\nkein platz mehr im speicher :'( \n");

	printf("\nausgabe von p: %s\n", p);

Alles klappt, obwohl ich nur 5Byte reserviere und viel mehr reinschreibe. Eigentlich hätte das so aussehen müssen:

PHP:
	char *p;

	p = malloc(5); //irgendwo 5Byte Reservieren

	if(p != 0) 
		strcpy(p, "ABCDEFGHIJKL");
	else {
        p = realloc(p, 10); //jetzt haben wir 15Byte
        printf("\nspeicherplatz wurde erweitert, neuer versucht :'(\n");
        //funktion neu aufrufen
       }
	printf("\nausgabe von p: %s\n", p);

Deswegen ist das ganze sinn vom Realloc nicht so klar. Man braucht es garnicht. Sehe ich das jetzt richtig, code okey? - gut man hätte es anders schreiben können, aber ich denke Ihr versteht was ich meine. Wer hätte jetzt einen sinnvollen Beispiel?

Danke und Gruß

Edit: Ok sehe, dass das mit dem Realloc strenggenommen da so eig. nicht funktioniert. Was ich damit sagen wollte ist, dass sobald mein 5Byte reservierte platz nicht ausreicht, sollte man eigentlich mit Realloc erweitern, was aber anscheinend unnötig ist, weil das system eh immer alles automatisch erweitert.
 
Zuletzt bearbeitet:
Also zunächst mal erweitert dein realloc aufruf den Speicher nicht UM 10 Byte sondern es werden nur irgendwo NEU 10 Byte Speicher reserviert und eventueller vorheriger Inhalt dorthin umkopiert.

Diese Funktionen sind allgemein dazu gedacht, dynamisch Speicher zu reservieren, z.b. wenn erst zur Laufzeit bekannt wird, wie gross ein Array werden soll.
Beispiel :
Der Benutzer soll double-Zahlen eingeben, die dann später sortiert werden sollen.
Wieviele Zahlen ("n") der Benutzer eingibt sei dem Benutzer freigestellt, und nur durch den vorhanden Speicher nach oben begrenzt.
Zuerst macht man sich dann einen Zeiger *zahlen auf double und initialisiert ihn am besten mit NULL.
Dann liest man die aktuell neueste Zahl in eine Hilfsvariable ein, reserviert dann Speicher für n+1 Zahlen und kopiert dann den Inhalt der Hilfsvariablen an die Stelle zahlen[n] usw.


Das ist der Sinn dieser Funktionen.

Das was du in deinem Code machst, funktioniert natürlich und wird vielleicht auch fehlerfrei zur Laufzeit funktionieren, aber eigentlich überschreibst du mit strcpy(p, "ABCDEFGHIJKL"); fremden Speicherbereich und das kann natürlich fatale Folgen haben.

Mach doch mal folgendes:
Definier dir noch einen char Zeiger und "malloce" auch 5 Byte direkt NACH deinem malloc Aufruf für p.

Dann weisst du ZUERST dem neuen Zeiger einen String zu und DANACH machst du deinen alten strcpy Aufruf für p.
Dann lässt du dir beide Strings ausgeben.
Sehr wahrscheinlich wirst du dann Teile des zweiten (später allozierten) Speicherbereichs/Strings mit dem ersten überschrieben haben.
 
Zuletzt bearbeitet:
skeemo schrieb:
Also zunächst mal erweitert dein realloc aufruf den Speicher nicht UM 10 Byte sondern es werden nur irgendwo NEU 10 Byte Speicher reserviert und eventueller vorheriger Inhalt dorthin umkopiert.

Moment um mich jetzt nicht weiter unnötig zu verwirren, ich dachte das bisher so:
Malloc = reserviert irgendwo einen Speicher mit größe x Bytes
Realloc = erweitert etwas mit größe x Bytes
Also 5Byte irgendwo wird mit Realloc(10Byte) erweitert ergibt dann 15Byte und nicht 10Byte irgendwo und der andere hat nichts mehr damit zutun.

Wenn du sagst mit Realloc werden nur irgendwo NEU 10 Byte speicher reserviert... dann würde ich gerne wissen was die unterschiede sind? DENN Malloc reserviert ja auch NEU im Speicher irgendwas und da wird eventuell was reinkopiert. Wenn das so wäre wie du da jetzt sagst, dann bräuchte man garkein Malloc - da Realloc das gleiche macht. Also entweder verstehe ich dich falsch oder die aussage ist falsch ^^

Vielleicht kann ja jemand was dazu sagen? Ist jetzt p 10byte oder 15byte(also wenn man p = realloc(p,10) macht)?

Gruß
 
XunnD : ganz genau

Wenn du sagst mit Realloc werden nur irgendwo NEU 10 Byte speicher reserviert... dann würde ich gerne wissen was die unterschiede sind? DENN Malloc reserviert ja auch NEU im Speicher irgendwas und da wird eventuell was reinkopiert. Wenn das so wäre wie du da jetzt sagst, dann bräuchte man garkein Malloc - da Realloc das gleiche macht. Also entweder verstehe ich dich falsch oder die aussage ist falsch ^^

Nein du hast mich richtig verstanden, aber deine Aussage ist falsch ;)
Malloc kopiert nämlich alte Speicherinhalte nicht um !
Bei einmaligen Aufruf ist natürlich kein Unterschied vorhanden. Aber wenn du mal wie in meinem Beispiel aufgeführt Speicherplatz dynamisch vergeben willst, dann ist das sehr wohl ein Unterschied, ob die bisher eingelesen Zahlen weg sind oder nicht :).

Das wird ja auch schon durch die Argumente von malloc und realloc klar.
malloc bekommt nur die Grösse des Speicherbereichs mit, kann also gar nicht wissen woher was kopiert werden soll , realloc bekommt aber genau aus diesem Grund auch noch die Adresse des alten Speicherbereichs mit...wie du das ja korrekterweise auch in deinem code praktiziert hast.

Übrigens wird nicht "irgendwo" Speicher alloziert sonder dort, wo welcher frei ist.
Eigentlich hilft einem eine saubere Verwendung der *alloc Funktionen deswegen, Speicherzugriffsverletzungen usw. zu verhindern bzw. Speichermangel abzufangen.

Also nochmal zusammengefasst :

Mit malloc kannst du nur einen fixen Speicherbereich allozieren.
Mit realloc kannst du einen "alten und zu klein/gross gewordenen" Speicherbereich vergrössern/verkleinern unter Berücksichtigung des "alten" Speicherbereichs / dessen Inhalt.

In beiden Fällen gibt man die ABSOLUTE Grösse des Speicherbereichs an.

Übrigens sollte man den Speicherbereich wenn man ihn denn nicht mehr braucht auch wieder frei geben.
Entweder mit free(p); oder mit p=realloc(p,0);

Und nochwas, ich persönlich finde es einen besseren Stil Zeiger nicht auf "0" sondern auf "NULL" zu vergleichen, das macht den Code sehr viel lesbarer. Aber da gibt es sicher auch andere Meinungen :)

so und als Hausaufgabe, programmierst du jetzt das von mir eingeführte Beispiel :)
 
Ah okey, glaube es hat *klick* gemacht...

war mir nicht klar, dass realloc alles in dem neuen Speicher rüberkopiert UND den anderen sogar noch freisetzt. Aus irgend einem Grund glaubte ich fest daran, dass mein mit malloc gemachter speicher noch da ist und das mit realloc einfach erweitert wird.

Gut gut, jetzt ergibt doch alles einen sinn. Vorallem die Speicher "verkleinerung" (oder auflösung) mit realloc, wie du es geschrieben hast realloc(p,0)

Ja jetzt bin ich motiviert genug und mache mal deine Aufgabe skeemo ;)

Danke Euch,

Gruß
 
Gut, auf realloc(x,0) als Ersatz für free(x) sollte man zuerst aus Gründen der Lesbarkeit verzichten. Mit free assoziiert man sofort eine Freigabe.
Desweiteren verwende ich lieber eine Funktion, die einen Parameter erwartet, als eine zweite, die exakt dasselbe macht, aber 2 Parameter erwartet.

Das Einsetzen von realloc statt free wäre dann sinnvoll, wenn man dadurch Speicher beim Linken sparen würde, weil jetzt beispielsweise eine Abhängigkeit gespart würde. Da aber beides Standard-Funktionen von C sind, löst sich das Argument in diesem speziellen Fall in Wohlgefallen auf.

Sofern der Compiler ein realloc(x,0) nicht zu free(x) optimiert, ist realloc(x,0) auch bezüglich der Performance keine Alternative zu free(x). Warum?
Selbst wenn realloc(x,0) nur free(x) aufrufen würde und dann zurückkehrte, hat man immer noch die an dieser Stelle unnötigen Stackoperationen, um den Funktionsaufruf von free in realloc zu realisieren. Zusätzlich hat man noch die Vergleiche, die feststellen, dass malloc nicht mehr benötigt wird (weil "0" Bytes angefordert werden).


Alles in Allem: realloc(x,0) als Ersatz für free(x) nicht ratsam.
 
Völlig korrekt !
Zu Anschauungszwecken im Rahmen des Thread-Problems hat die Erwähnung von realloc(x,0) denke ich aber zum Verständnis der Funktionsweise von realloc beigetragen.

Im Sinne der Performance macht es natürlich ebensowenig Sinn für jedes neue zu speichernde Element jetzt extra neuen Speicher zu allozieren (in meinem Beispiel mit dem dynamischen Double-Array dann also für jede neue double-Zahl).
Man sollte vielmehr immer gleich blockweise Platz für mehere "Zahlen" reservieren und erst bei erneuten Erreichen dieser "Blocksize" wieder neuen Speicher allozieren.
Inwieweit eventuelle Speicherplatzverschwendung gegenüber Performanceverlusten besser dasteht ist in der jeweiligen Umgebung / Anwendung und Anforderung zu entscheiden.

An den Threadersteller noch ein Tip :
Man benutzt gerne auch anstatt absoluten Byteangaben die Funktion sizeof() an dieser Stelle.
z.B. wenn du Platz für 10 Integers brauchst dann machs einfach so :

p = malloc(sizeof(int)*10); // entsprechend mit realloc!

So bist du auf jeden Fall auf der sicheren Seite, falls du aus welchen Grund auch immer für Integer jetzt eine falsche Byteanzahl annimmst.
 
Ich halte es zudem für wenig sinnvoll, für lokale Variablen von Bytemengen unter 1000 Bytes Speicher im Heap zu alloziieren. Sowas kann und sollte - ebenfalls aus Geschwindigkeitsaspekten - auf dem Stack angelegt werden. Es sei denn, der Speicherbereich soll außerhalb der Funktion noch gültig bleiben.

Du musst bedenken, dass mit jedem Speicherbereich zusätzliche Verwaltungs-Informationen gespeichert werden.
 
Ja, wie gesagt, alles im Sinne des Topics :)
 
Gebe ja auch nur Tipps und meine Erfahrungen weiter :)
 
Na dann ist doch alles dufte :)
 
Zurück
Oben