C Dummie braucht Zeiger/Speicher-Nachhilfe
-
Serethos schrieb:
Einige Fälle zur Speicherverwaltung und zu Zeigern sind mir noch nicht ganz klar.
Wenn in einer Funktion ein Pointer zu einer lokalen Variable zurückgegeben wird, wird der Speicherplatz dieser Variable dann gelöscht und der rückgegebene Pointer ist ungültig oder sorgt der aufrechterhaltene Pointer dafür, dass der Speicherplatz bestehen bleibt?
Ersteres. Lokale Variablen werden nach Verlassen der Funktion gelöscht. Pointer, die darauf zeigen, werden ungültig. Dein Programm fällt in einen undefinierten Zustand, wenn du versuchst, den Pointer zu dereferenzieren.
Folgendes funktionier nämlich:
int* test() { int i = 10; return &i; } void main() { cout << *test(); }
Aber ist das nur Zufall, da der freigegebene Speicherplatz noch nicht überschrieben worden ist?
Jap. Das Programm hätte auch mit Ach und Krach abstürzen können.
ESS_CB schrieb:
cout << *inte; // ich glaub das * kannst du auch weglassen (??) }
Wenn du das * weglässt, gibst du die Adresse des Pointers aus, nicht das, auf was er zeigt. Im Übrigen sind wir hier im ANSI C Forum und cout ist C++. Und es heißt int main, nicht void main: http://www.c-plusplus.net/forum/viewtopic-var-t-is-39346.html
Ich verweise auch mal auf meinen Artikel zum Thema Pointer: http://www.c-plusplus.net/forum/viewtopic-var-t-is-124532.html
Dort dürften die meisten Fragen beantwortet werden...EDIT: zu lahm.
MfG
GPC
-
Danke für die Antworten. Dann habe ich aber noch eine Anschlußfrage, die ich mir ducht das Zeiger-Tutorial nicht beantworten konnte. Ich habe mir hier schonmal Hilfe geholt, um einen eigenen Tokenizer zu schreiben. Dieser gibt einen Token (lokales char-Feld) als Zeiger wieder zurück, in etwa:
char* tokenize(char* str, char* delims) { static char tokens[256]; // tokenize .. return buf; }
Hier ist die Zeigerrückgabe einer lokal deklarierten Variable ja legitim, da static ein Löschen von 'tokens' verhindert. Ähnlich müsste es sich ja auch verhalten, wenn ich buf über malloc in den heap geschrieben hätte.
Nur um sicher zu gehen, das bedeutet, die Pflicht, tokens wieder freizugeben (free)liegt beim Aufrufer, solange dioe Funktion tokenize es nicht selbst tut (was sie in meinem Fall zwar macht, aber .. naja, generell).Vielleicht mal ein klareres Beispiel:
char* produceString() { static char txt[10]; // irgendwas in txt reinschreiben return txt; }
Hier muss sich ja der Aufrufende ums Aufräumen kümmern(?)
Und was geschieht mit static Variablen, die nicht zurückgeliefert, sondern nur intern (z.B. ein Zähler) genutzt werden. Bleiben die dann bis zum Exitus im Speicher?
Außerdem, worin besteht dann der Unterschied zwiuschen 'static' und der heap-Reservierung der Variable über 'malloc'?
-
"static" Variablen liegen in einem eigenen Speicherbereich (zusammen mit globalen Variablen des Programms), da kümmert sich die main() selber darum, am Programmende aufzuräumen.
Mit malloc() angelegte Variablen landen auf dem Heap, da mußt du dich um die Freigabe kümmern, wenn du den Platz nicht mehr brauchst.
(OK, eigentlich kümmert sich das Betriebssystem um die nötigen Aufräumarbeiten, aber auf Dauer dürfte es unter dem Haufen unerreichbaren Speicher zusammenbrechen)
-
Hmm, das ist ja ärgerlich! Ich bin den Garbage Collector von Java gewöhnt. Somit bleiben ja all die (hochnotwendigen!) static Variablen, auf die der Aufrufende keinen Zugriff hat eventuell im Speicher kleben, bis main beendet wird..
-
also die 'main' macht eigentlich gar nix (nur was man da selbst reinprogrammiert hat)
-
net schrieb:
also die 'main' macht eigentlich gar nix (nur was man da selbst reinprogrammiert hat)
CStoll schrieb:
"static" Variablen liegen in einem eigenen Speicherbereich (zusammen mit globalen Variablen des Programms), da kümmert sich die main() selber darum, am Programmende aufzuräumen.
Aber eine Frage habe ich eh noch. Mein Tokenizer der Marke:
char* tokenize(char* str, char* delims) { static char tokens[256]; // tokenize .. return buf; }
nutzt nun ja einen static Zeiger auf eine char-Kette. Nun bin ich auf einen Nebeneffekt reingefallen. Auf Seite des Aufrufers werden die Token nämlich wieder ein einem Array von strings gespeichert. Weil ja aber der Zeiger 'tokens'
konstant die selbe Speicheradresse benutzt, ändern sich alle Inhalte des Arrays auf Aufrufseite gleich mal mit.
Ich kann es natürlich lösen, indem ich statt static zu nutzen 'tokens' auf dem heap alloziere. Ich hätte nur gerne eine Bestätigung, dass es keinen anderen, gängigeren Weg gibt.
-
Serethos schrieb:
Ich kann es natürlich lösen, indem ich statt static zu nutzen 'tokens' auf dem heap alloziere. Ich hätte nur gerne eine Bestätigung, dass es keinen anderen, gängigeren Weg gibt.
gib der funktion einen pointer auf den speicherbereich, den sie füllen bzw. benutzen soll (und eventuell die länge). dann biste unabhängig von der art der speicherreservierung...
-
net schrieb:
also die 'main' macht eigentlich gar nix (nur was man da selbst reinprogrammiert hat)
OK, da habe ich mich wohl etwas locker ausgedrückt: Der Compiler setzt um deine main() noch etwas eigenen Code, unter anderem zur Initialisierung der globalen Variablen, zum Parsen der Befehlszeile (argc/argv) etc - und auch um statische Variablen am Programmende wieder aufzuräumen.
(letzteres ist vor allem für C++ Programme wichtig, bei denen der Destruktor aufgerufen werden muß)
-
Naaajaaa, ich finde, das ist nun wirklich Haarspalterei .. ich denke, in dem Punkt hab ich es schon korrekt verstanden ..
-
sorry sorry, hätte ich wissen müssen mit dem *