Hallo, wenn ich einen Speicherbereich mit calloc alloziere, also z.B. uint8_t xyz = (uint8_t*) calloc(sizeof(uint8_t), 10); dann gebe ich den ja danach wieder mit free(xyz) frei. Muss ich das auch mit jedem von mir erzeugten Pointer tun, oder sind "normal" erzeugte Pointer, die nicht mit calloc / malloc erzeugt wurden immer lokal, so dass sie ohnehin wieder freigegeben werden? Hintergrund ist, dass ich einen String habe, z.B. bei xyz. Dann setzte ich eine Reihe an Pointern auf diesen String an, um innerhalb des Strings bestimmte Keywörter zu suchen. Muss ich diese Pointer eigentlich auch wieder freigeben?
Hi, du musst dir überlegen, was du das eigentlich freigeben willst. Du musst den "Speicherbereich" auf den der Pointer zeigt freigeben, und nicht den Pointer an für sich. Wichtig ist halt, das du dann sicherstellen musst, das du nicht mehr von dem Speicher liest/schreibst, wenn er freigegeben wurde.
Pointer schrieb: > Hallo, > > Muss ich das auch mit jedem von mir erzeugten Pointer tun, oder sind Ein Pointer wird nicht "erzeugt". Der existiert in C per Variablendefinition. > "normal" erzeugte Pointer, die nicht mit calloc / malloc erzeugt wurden > immer lokal, so dass sie ohnehin wieder freigegeben werden? Ein Pointer ist eine ganz normale Variable, da gelten die gleichen Regeln wie für jede beliebige andere definierte/deklarierte Variable, z.B. vom Typ "int"!
Wenn der Pointer eine lokale Variable ist (in der Funktion deklariert), musst du garnichts machen. Sie ist auf dem Stack, der Platz wird nach Verlassen der Funktion für andere Daten verwendet. Bei Mehrfachverwendung eines Pointers ist es sinnvoll, ihn auf NULL zu setzen, wenn sein Speicherbereich freigegeben wird. Dadurch sind fehlerhafte Zugriffe schneller erkennbar.
Pointer schrieb: > wenn ich einen Speicherbereich mit calloc alloziere, also z.B. > uint8_t xyz = (uint8_t*) calloc(sizeof(uint8_t), 10); > dann gebe ich den ja danach wieder mit free(xyz) frei. So weit, so korrekt. > Muss ich das auch mit jedem von mir erzeugten Pointer tun, oder sind > "normal" erzeugte Pointer, die nicht mit calloc / malloc erzeugt wurden > immer lokal, so dass sie ohnehin wieder freigegeben werden? Du hast da ein massives Verständnisproblem. > Hintergrund ist, dass ich einen String habe, z.B. bei xyz. > Dann setzte ich eine Reihe an Pointern auf diesen String an, um > innerhalb des Strings bestimmte Keywörter zu suchen. > Muss ich diese Pointer eigentlich auch wieder freigeben? Ein Pointer ist eine hundsgewöhnliche Variable. Nicht anders als ein int oder double. Und wie jede andere Variable mußt du den Pointer selbst weder erzeugen noch freigeben. Variablen werden vom Compiler erzeugt und (möglicherweise) wieder freigegeben, abhängig von ihrer Speicherklasse. Das ist ein etwas verallgemeinertes Konzept der Lebensdauer einer Variablen. Automatische Variablen (die Default-Speicherklasse) sind innerhalb eines Blocks definiert (z.B. einer Funktion oder auch dem Rumpf einer for-Schleife). Diese Variablen "leben" nur innerhalb des Blocks und der Compiler erzeugt sie, wenn der Programmfluß in den Block eintritt und zerstört sie, wenn der Block verlassen wird. Das Gegenteil sind globale Variablen, die während der gesamten Ausführung des Programms existieren und folglich nie zerstört werden. So weit, so einfach. Bei Pointern kommt nun dazu, daß sie nicht nur an sich existieren, sondern auch auf etwas zeigen. Dieses etwas kann z.B. eine andere Variable sein:
1 | int x= 42; /* eine "normale" Variable */ |
2 | int *p= &x; /* und ein Pointer auf die Variable */ |
An dieser Stelle hast du auch noch nicht viel zu tun. Der Compiler erzeugt (und zerstört) Variable und Pointer automatisch. Worauf du aber achten mußt: der Pointer sollte nicht länger leben als die Variable auf die er zeigt. Denn sonst kann es passieren, daß die Variable schon zerstört ist, der Pointer jedoch nicht. Der Pointer zeigt dann "ins Nichts" und ein Zugriff auf dieses "Nichts" über den Pointer führt mindestens zu undefiniertem Verhalten, mit etwas Pech (manche sagen: Glück) zum Absturz des Programms. Nochmal anders ist die Situation, wenn du einen Speicherbereich mit *alloc() anforderst und an einen Pointer bindest. Im Gegensatz zu einer Variablen hat dieser Speicher keine Speicherklasse (vulgo: Lebensdauer). Er existiert von dem Moment an, wo du ihn anforderst, so lange bis du ihn freigibst (oder auch nicht). Insbesondere gibt der Compiler keinen Speicher frei, wenn er einen Pointer zerstört, der darauf zeigt. Dieses Feature heißt Garbage Collection und ist unter C(++) Programmierern aus verschiedensten Gründen umstritten bis verpönt. Schlußfolgerung: wenn du Speicher mit *alloc() allozierst und an einen Pointer bindest, dann mußt du diesen Speicher mit free() wieder freigeben, bevor der Pointer (womöglich automatisch) zerstört wird. Wenn du das nicht tust, wird der allozierte Speicher für dich unbenutzbar, insbesondere kannst du ihn auch nicht mehr freigeben. Dein Programm hat jetzt ein Speicherleck (memory leak). Das mag auf den ersten Blick kein Beinbruch sein, ist unter Programmierern aber genauso "beliebt", wie Leute die sich Bücher ausborgen und dann nie zurück bringen.
Axel S. schrieb: > Insbesondere gibt der > Compiler keinen Speicher frei, wenn er einen Pointer zerstört, der > darauf zeigt. Dieses Feature heißt Garbage Collection und ist unter > C(++) Programmierern aus verschiedensten Gründen umstritten bis verpönt. Kleine Korrektur: Dieses Feature heißt Smart Pointer und ist spätestens seit C++11 nicht mehr umstritten. Ein std::unique_ptr kostet keinerlei Overhead, verhindert aber wirksam Memory/Resource-Leaks, auch wenn Exceptions im Spiel sind. Verpönt sind gewöhnliche Pointer, denen einen Objekt gehört ("owning RAW pointer"), das zerstört werden muss, wenn der Pointer aus dem Scope geht. Garbage Collection ist dagegen ein eigener Thread/Prozess, der zu unvorhersehbaren Zeitpunkten den Speicher des Prozesses nach Objekten durchsucht, auf die keine Pointer mehr zeigen und diese zerstört. Das braucht man in C++ nicht, denn das erledigen Smart-Pointer effizienter und vor allem deterministisch, d.h. genau dann, wenn sie aus dem Scope gehen und nicht irgendwann später.
Hans schrieb: > Axel S. schrieb: > >> Insbesondere gibt der >> Compiler keinen Speicher frei, wenn er einen Pointer zerstört, der >> darauf zeigt. Dieses Feature heißt Garbage Collection und ist unter >> C(++) Programmierern aus verschiedensten Gründen umstritten bis verpönt. > > Kleine Korrektur: Dieses Feature heißt Smart Pointer und ist > spätestens seit C++11 nicht mehr umstritten. Jein. Ein Smart Pointer ist eine weitere mögliche Variante (neben Garbage Collection), um Speicher automatisch freizugeben. Und in der Tat waren Smart Pointer unter C++ Programmierern nie umstritten. In C gibt es sie schlicht nicht. Allerdings sind Smart Pointer in ihrer Funktion eingeschränkt, denn sie funktionieren nur dann, wenn auf einen Speicherbereich immer nur ein Smart Pointer zeigt. Wenn zwei Smart Pointer unabhängig auf den gleichen Speicher zeigen, dann funktioniert das Reference Counting nicht mehr. Das Beispiel was ich oben genannt habe, kann ein Smart Pointer natürlich, aber das war ja auch absichtlich vereinfacht, um den TE nicht zu überfordern. In der Praxis hat man oft deutlich komplexere Strukturen als nur ein Stück Speicher und genau einen Pointer darauf. > Garbage Collection ist dagegen ein eigener Thread/Prozess Das ist ein Implementierungsdetail. Z.B. der Boehm-GC [1] läuft in seiner einfachsten Variante als Teil des aufrufenden Prozesses. > der zu > unvorhersehbaren Zeitpunkten den Speicher des Prozesses nach Objekten > durchsucht, auf die keine Pointer mehr zeigen und diese zerstört. Das > braucht man in C++ nicht, denn das erledigen Smart-Pointer effizienter > und vor allem deterministisch Das ist genau der Grund, warum offline GC verpönt sind. [1] https://de.wikipedia.org/wiki/Boehm-Speicherbereinigung
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.