char Pointer, ich verstehe da etwas nicht...
-
sunnyandy schrieb:
Meine zweite Frage: Wird in Beispiel 2 die Variable "char* name" nach Verlassen der Funktion wieder zerstört? Also kann es passieren, dass der Pointer ungültig wird?
Der Pointer wird zerstört, da er seinen Gültigkeitsbereich verlässt, aber sein Wert, also die Adresse die er enthält wird in den Rückgabewert kopiert.
Im Allgemeinen ist dieses Vorgehen auch böse, da der Aufrufer der Funktion daran denken muss den Speicher, der mit new angefordert wurde auch wieder zu löschen ( ... und noch weitere Probleme ).
-
Unter C++ hat man zum Glück die Möglichkeit,
std::stringeinzusetzen, was man auch nutzen sollte.
-
KasF schrieb:
Der Pointer wird zerstört, da er seinen Gültigkeitsbereich verlässt, aber sein Wert, also die Adresse die er enthält wird in den Rückgabewert kopiert.
Im Allgemeinen ist dieses Vorgehen auch böse, da der Aufrufer der Funktion daran denken muss den Speicher, der mit new angefordert wurde auch wieder zu löschen ( ... und noch weitere Probleme ).Das heißt, der Inhalt im Speicher bleibt erhalten?
Ich hatte mir nämlich folgendes Tutorial durchgelesen:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-124532.htmlNatürlich kann man Zeiger auch als Return-Werte einsetzen, allerdings muss man unbedingt sicherstellen, dass die Variable, auf die der Zeiger verweist, auch nach dem Verlassen der Funktion noch existiert, sonst wird unser Programm beim Zugriff auf den Zeiger abschmieren:
int * increment(int i) { int var = i; ++var; return &var; };//hier wird var zerstört, wohin zeigt der Pointer jetzt??
Wenn man jetzt versucht den Zeiger zu dereferenzieren, wird das Programm mit Sicherheit (irgendwann) mit einem Segmentation Fault abstürzen!
Eine Lösung wäre var static zu deklarieren, um sicherzustellen, dass die Variable auch nach Verlassen der Funktion noch existiert:
...Dort wird beschrieben, dass ich hinterher auf die Speicheradresse nicht mehr zugreifen kann. Heißt das also, ich sollte in Funktionen, die Pointer zurückgeben, die Rückgabe-Variable immer static deklarieren? Mir kommt das etwas komisch vor...
-
sunnyandy schrieb:
KasF schrieb:
Der Pointer wird zerstört, da er seinen Gültigkeitsbereich verlässt, aber sein Wert, also die Adresse die er enthält wird in den Rückgabewert kopiert.
Im Allgemeinen ist dieses Vorgehen auch böse, da der Aufrufer der Funktion daran denken muss den Speicher, der mit new angefordert wurde auch wieder zu löschen ( ... und noch weitere Probleme ).Das heißt, der Inhalt im Speicher bleibt erhalten?
Ich hatte mir nämlich folgendes Tutorial durchgelesen:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-124532.htmlNatürlich kann man Zeiger auch als Return-Werte einsetzen, allerdings muss man unbedingt sicherstellen, dass die Variable, auf die der Zeiger verweist, auch nach dem Verlassen der Funktion noch existiert, sonst wird unser Programm beim Zugriff auf den Zeiger abschmieren:
int * increment(int i) { int var = i; ++var; return &var; };//hier wird var zerstört, wohin zeigt der Pointer jetzt??
Wenn man jetzt versucht den Zeiger zu dereferenzieren, wird das Programm mit Sicherheit (irgendwann) mit einem Segmentation Fault abstürzen!
Eine Lösung wäre var static zu deklarieren, um sicherzustellen, dass die Variable auch nach Verlassen der Funktion noch existiert:
...Dort wird beschrieben, dass ich hinterher auf die Speicheradresse nicht mehr zugreifen kann. Heißt das also, ich sollte in Funktionen, die Pointer zurückgeben, die Rückgabe-Variable immer static deklarieren? Mir kommt das etwas komisch vor...
Muss nicht static sein. Die variable darf halt nicht nur lokal in der Funktion existieren sondern muss irgendwo zB stack oder so liegen damit sie nach Verlassen der Funktion noch existiert.
-
Pigeon schrieb:
Dort wird beschrieben, dass ich hinterher auf die Speicheradresse nicht mehr zugreifen kann. Heißt das also, ich sollte in Funktionen, die Pointer zurückgeben, die Rückgabe-Variable immer static deklarieren? Mir kommt das etwas komisch vor...
Muss nicht static sein. Die variable darf halt nicht nur lokal in der Funktion existieren sondern muss irgendwo zB stack oder so liegen damit sie nach Verlassen der Funktion noch existiert.[/quote]
Vermutlich meinst du 'Heap', nicht 'Stack'. Nicht?
-
sunnyandy schrieb:
(...)
Nun gibt es aber wie bei Gtk Methoden die einen char Pointer erwarten:GtkWidget* gtk_label_new (const char *str);Dort erzeuge ich mir doch auch ein Label mittels
myLabel = gtk_label_new("LabelBezeichnung");Nun meine Frage:
Warum kann ich bei Gtk eine Zeichenkette übergeben, die ich vorher in keiner Variablen als Pointer gespeichert habe? Und warum ist das auf der anderen Seite wie in Beispiel 1 falsch?
(...)"LabelBezeichnung" existiert (als Literal) während der gesamten Programmlaufzeit. Man muss nur wissen wo => durch Pointer (Zeiger). Den Pointer auf das Literal übergibst du der Funktion gtk_label_new.
Hinweis: Wenn du String-Literale wie "LabelBezeichnung" definierst, so sind diese vom Typ const char.*
gtk_label_new wird (wahrscheinlich) nun die Werte (char) aus der Zeichenkette kopieren und mit diesen Kopien weiterarbeiten. So ist es später nicht mehr von Belang, was mit der übergebenen Zeichenkette passiert.
Der andere Fall, die Rückgabe eines Pointers auf einen Wert, welcher lediglich innerhalb des Funktionsaufrufes existiert, ist deshalb nicht möglich, weil der Wert nach dem return (explizit oder implizit bei void-Funktionen) nicht mehr existiert ("isso!" || ("stack vs heap", "Parameterübergabe über Stack").
Wenn du nun Zeichenketten (sicher) zurückgegeben willst, muss du diese kopieren. Am besten nimmst du, wie schon erwähnt, die Standardklasse std::string. Diese übernimmt das Anfordern und Freigeben von Speicher für dich:
std::string /* Kopie */ getTheString() { return "Hallo Welt!"; // oder: return std::string("Hallo Welt"); }Hinweis: Die Klasse std::string bringt eine Methode c_str() : const char mit. Diese wirst du benötigen, wenn du deine Zeichenketten an Funktionen weitergeben willst, welche einen const char* verlangen:*
// ... std::string myString("Hassenichjesehen"); myLabel = gtk_label_new(myString.c_str()); // ...Keine Panik vor Kopien. Soviel Performance kosten diese nun auch wieder nicht.
Grüße... Heiko
-
Hallo,
danke für die tollen Antworten!Mir ist noch nicht ganz klar, wann ein im Speicher liegendes Objekt freigegeben wird.
Nehmen wir an, ich habe eine Main-Methode:
int main (int argc, char *argv[]) { MyObject *mo = new MyObject(); MyWindow *mw = new MyWindow(mo); }MyWindow::MyWindow(MyObject *mo) { this->myObject = mo; }Nun ist meine Frage folgende: Wenn die Main-Methode durchlaufen ist, werden die Variablen mo und mw doch zerstört. Was passiert mit den dahinterliegenden Objekten im Speicher?
In MyWindow kann ich doch dann unbedenktlich mit MyObject arbeiten, richtig?
-
sunnyandy schrieb:
Nun ist meine Frage folgende: Wenn die Main-Methode durchlaufen ist, werden die Variablen mo und mw doch zerstört. Was passiert mit den dahinterliegenden Objekten im Speicher?
In MyWindow kann ich doch dann unbedenktlich mit MyObject arbeiten, richtig?mo und mw (nur Pointer) werden zerstört, ja. Die Objekte bleiben unbehelligt bestehen. Du kannst beliebig mit denen weiterarbeiten. Solltest du aber deine letzte Referenz (eher Pointer) auf diese löschen, hast du keine (saubere) Möglichkeit mehr diese anzusprechen und hast dein erstes Memory Leak.

-
Fellhuhn schrieb:
sunnyandy schrieb:
Nun ist meine Frage folgende: Wenn die Main-Methode durchlaufen ist, werden die Variablen mo und mw doch zerstört. Was passiert mit den dahinterliegenden Objekten im Speicher?
In MyWindow kann ich doch dann unbedenktlich mit MyObject arbeiten, richtig?mo und mw (nur Pointer) werden zerstört, ja. Die Objekte bleiben unbehelligt bestehen. Du kannst beliebig mit denen weiterarbeiten. Solltest du aber deine letzte Referenz (eher Pointer) auf diese löschen, hast du keine (saubere) Möglichkeit mehr diese anzusprechen und hast dein erstes Memory Leak.

Richtig. Aber um das auch noch anzumerken. Wenn main durchlaufen ist, wird sehr wahrscheinlich alles von deinem OS wieder aufgeräumt. Das soll jetzt aber nicht so sein, dass du dich darauf verlässt, sollte nur als Ergänzung dienen.
Wenn du jetzt zum Beispiel ein einem lang laufenden Programm den Speicher nie aufräumst, kann es sein, dass dir das in kürzester Zeit zum Verhängniss wird.
-
Und beim Beenden des Programms hat man auch schön lange Wartezeiten. Ist mir selber schon passiert, dass ich während der Laufzeit eines Programms nach und nach den Arbeitsspeicher geflutet habe, ohne es zu merken. Naja, beim Beenden wars dann ein wenig mühsam. Was auch immer gut ist, wenn man den Arbeitsspeicher bereits überfüllt hat und die Auslagerungsdatei vergrössern muss...