Wann muss man speicher auf dem heap allokieren?
-
Hallo!
Zur heapallokierung verwendet ja man malloc. Und die Stack allokierung wie sieht die aus? Erklärt mir den Unterschied bitte.
Ich habe folgendes Bsp:
Angenommen ich habe flächeninhalte von verschiedenen Quadraten berechnet. und auf Diese Werte lass ich jetzt einen pointer draufzeigen..., da es mehrere Werte sind als einer muss ich schreiben: malloc=(sizeof(flaeche)*anz der flächen), wenn ich jetzt nur einen Flächeninhalt habe und eine pointer draufzeigen lassen, dann wird der speicher automatisch geholt... richtig?Im Vergleich zu:
Jetzt das gleiche nur mit einer Struktur...
Man hat nur eine Struktur --> pointer=malloc(sizeof(struktur)) -> umsonst oder?
Und mehrere --> pointer=malloc(sizeof(struktur)*anzahl)Ich glaube ich hab das noch net ganz kapiert... Erklärt mir das bitte
Danke im voraus!
mfg man_in_black
-
malloc reserviert bei erfolgreicher Ausführung die angegebene Anzahl Bytes für dich. Das nennt man dynamische Speicherreservierung. Speicherreservierung per Definition von Objekten (Variablen verschiedener Typen, struct, Array, auch Pointertypen) steht dem gegenüber.
Im Standard steht nichts von Heap, Stack, Code/Daten/Text-Segment usw.
Bei dynamischer Speicherreservierung bist du selbst für die Freigabe verantwortlich, im anderen Fall wir für dich "automatisch" aufgeräumt am Ende des Codeblocks, bei globalem Sichtbarkeitsbereich oder static Speicherklasse am Ende des Programms/Prozesses.
-
Ok, danke, aber muss man nun speicher allokieren mittels malloc, wenn man EINE struktur hat wo ein pointer draufzeigt?
Wenn ein pointer z.B. auf EINEN interger, float etc. variable zeigt braucht man kein malloc es funktioniert ohne!
-
man_in_black schrieb:
Zur heapallokierung verwendet ja man malloc. Und die Stack allokierung wie sieht die aus? Erklärt mir den Unterschied bitte.
Die Allokation auf dem Stack wird vom Compiler übernommen. Genau genommen ist das auch nur der "automatische" Speicher, der aber üblicherweise als Stack implementiert wird. (Im Gegensatz zum "dynamischen" Speicher, der üblicherweise als Heap implementiert ist.)
Wird dein Programm gestartet, wird ihm automatisch x Byte an Speicher zugewiesen, das ist dann der Stack. Dein Programm kennt einen Pointer auf das erste Byte. Deswegen entspricht das "reservieren" und "freigeben" auf dem Stack auch nur einer Addition/Subtraktion und ist dadurch sehr schnell.
void foo(void) { // sizeof(double) Byte werden auf dem Stack reserviert double p; } // sizeof(double) Byte werden wieder freigegeben int main(void) { // sizeof(int) + sizeof(char) * 300 Byte werden auf dem Stack reserviert int i; char c[300]; foo(); } // sizeof(int) + sizeof(char) * 300 Byte werden wieder freigegeben
Genau genommen läuft auf dem Stack sogar noch etwas mehr ab, es werden z.B. die Rücksprungadressen abgespeichert. (Deshalb können gezielte Bufferoverflows zu Exploits werden.)
So, der Stack hat aber ein paar Nachteile:
1. Er ist nicht besonders groß. (Auf Windows üblicherweise 1 MB pro Thread.)
2. Er hat eine völlig "lineare" Struktur. Du kannst also nichts freigeben, was unter noch reserviertem Speicher liegt. Alles hat also einen klare Lebenszeit.
(In C die geschweiften Klammern.)Wenn du also entweder sehr viel (bzw. beliebig viel) Speicher brauchst, oder du keinen Scope hast, reservierst du auf dem Heap.
Anmerkung: Das hier ist nur in Ausnahmefällen eine gute Idee:
struct A* create_something(void) { struct A* p = malloc(...); ... return p; }
Wenn möglich, sollte die Instanz die reserviert den Speicher auch wieder freigeben.
-
man_in_black schrieb:
Wenn ein pointer z.B. auf EINEN interger, float etc. variable zeigt braucht man kein malloc es funktioniert ohne!
Das funktioniert aber nur wenn du auch vorher eien entsprechende Variable definiert hast, auf die der Zeiger zeigt.
Und da ist kein Unterschied zu den Strukturen.
-
[quote="DirkB"]
man_in_black schrieb:
Und da ist kein Unterschied zu den Strukturen.
Also wenn ich vorher schreibe:
struktur* pointer=NULL;
Und der pointer nur auf EINE Struktur ZEIGT, dann brauch ich nicht malloc verwenden?
Wenn ich aber pointer auf mehrere verschiedene Strukturen zeigen lasse, dann muss ich malloc verwenden und mit pointer++ zeigt der pointer dann auf die nächste Struktur.
Korrekt?
-
Ein Zeiger verweist auf eine Adresse im Speicher.
Hantierst du mit dem Zeiger herum, liest/schreibst/inkrementierst muss der Compiler (d.h. zur Compilezeit!) wissen, wieviel Speicher ab der Adresse er bearbeiten muss, d.h. sizeof(TypAufDenDerZeigerZeigt) muss bekannt sein.int i; int *pi; pi = &i; /* Zeiger zeigt auf Anfangsadresse des oben definierten Speicherbereiches der Variablen i, d.h. kein malloc etc. nötig, da Speicher schon reserviert! */ i=5; printf("%d %d",i,*pi); /* beides 5 */ *pi=6; printf("%d %d",i,*pi); /* beides 6 */
Wenn keine Variable, die ihren eigenen Speicher durch ihre Definition schon "mitbringt" vorhanden ist, musst du diesen Speicher selbst belegen, z.B. mit malloc.
typedef struct { int i,j,k; } Typ; Typ *pt; /* pt zeigt irgendwo hin, d.h. ein Zugriff auf den Zeiger bringt nichts */ pt = malloc( sizeof(*pt) ); /* Es werden sizeof(Typ) Bytes reserviert und pt zeigt dahin */ pt->i=1; pt->j=2; pt->k=3; printf("%d %d %d",pt->i,pt->j,pt->k); pt++; /* pt zeigt jetzt auf die (aligned) Adresse nach dem oben definierten Speicherbereich, der ist aber NICHT für dich reserviert!! d.h. ein Zugriff darauf geht schief, im BESTEN Fall erhälst du eine Fehlermeldung */ printf("%d %d %d",pt->i,pt->j,pt->k);
void *p; p++; /* das hier geht gemäß Standard schief, da der Compiler nicht weiß, wieviele Bytes/Adressen er den Zeigerwert erhöhen soll, d.h. sizeof(void) ist normalerweise unbekannt */
-
man_in_black schrieb:
struktur* pointer=NULL;
Und der pointer nur auf EINE Struktur ZEIGT, dann brauch ich nicht malloc verwenden?Im Augenblick zeigt er auf keine Struktur.
Da ist aber auch kein Unterschied zuint *zeiger = NULL;
Bei
struktur StrukturVariable; struktur *pointer=&StrukturVariable;
zeigt pointer auf eine Struktur und das ganze ohne malloc.
-
Ok, danke und warum muss man nochmal festlegen ob nun der pointer ein integer, float etc. ist?
Das er beim pointer++; um die richtige Byteanzahl weiter hüpft oder?
-
man_in_black schrieb:
Dass er beim pointer++; um die richtige Byteanzahl weiter hüpft oder?
Deswegen kannst du z.B. einen void* nicht inkrementieren. Und nicht dereferenzieren(!). Aber ein wichtiger Grund ist auch Typsicherheit, du willst so etwas nicht ohne Warnung/Fehler schreiben können:
int* i = .. double* d = i; // Höchst wahrscheinlich autsch. Wenn man das wirklich will, castet man.