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
intx=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