Forum: Mikrocontroller und Digitale Elektronik Pointer freigeben?


von Pointer (Gast)


Lesenswert?

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?

von Marcus P. (marc2100)


Lesenswert?

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.

von Required Field (Gast)


Lesenswert?

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"!

von Jobst Q. (joquis)


Lesenswert?

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.

von Axel S. (a-za-z0-9)


Lesenswert?

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.

von Hans (Gast)


Lesenswert?

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.

von Axel S. (a-za-z0-9)


Lesenswert?

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
Noch kein Account? Hier anmelden.