Verständnisfrage zu Pointern
-
Hallo,
es geht um folgenden Code
#include <iostream> using namespace std; void foo(int **pPointer2) { int Zahl=2; *pPointer2=&Zahl; } int main() { int Zahl2=0; int *pPointer1; pPointer1 =&Zahl2; foo(&pPointer1); cout << "Zahl: " << *pPointer1 << endl; return 0; }Hier mal mein Gedankengang zu dem was ich gemacht habe:
Ich erzeuge einen Pointer und setze ihn auf die Adresse von Zahl2.
Jetzt übergebe ich die Adresse auf die der Pointer zeigt an foo().
Diese erzeugt einen Doppelpointer **pPointer2 und setzt diesen auf die übergebene Adresse.
Nun biege ich den Inhalt von pPointer2 (also den inneren Zeiger) auf die Adresse von Zahl2 um. Damit zeigt pPointer2 letztendlich auf die Adresse von Zahl2.Wieso biegt es nun auch pPointer1 auf Zahl2 um? Diesen hab ich doch gar nicht verändert? Ich habe doch lediglich die Adresse des Pointers kopiert und der andere pPointer2 zeigt nun halt auch noch auf diese Adresse.
Vielen Dank für Eure Antworten
-
bacon schrieb:
Jetzt übergebe ich die Adresse auf die der Pointer zeigt an foo().
Diese erzeugt einen Doppelpointer **pPointer2 und setzt diesen auf die übergebene Adresse.Nein, du übergibst die Adresse des Pointers. Da wird nichts "erzeugt". Dann veränderst du den Pointer und machst ihn mit der Zuweisung einer lokalen Adresse außerhalb der Funktion ungültig.
-
Das hab ich verstanden. Ich sehe nur immernoch nicht den Zusammenhang wieso *pPointer1 eine 2 (aus foo() ) ausgibt.
-
bacon schrieb:
Das hab ich verstanden.
steht im Widerspruch zu
Ich sehe nur immernoch nicht den Zusammenhang wieso *pPointer1 eine 2 (aus foo() ) ausgibt.
-
bacon schrieb:
Ich sehe nur immernoch nicht den Zusammenhang wieso *pPointer1 eine 2 (aus foo() ) ausgibt.
Naja du hast deinen Pointer in der foo() Funktion überschrieben und so geändert, dass er auf eine lokale Variable zeitgt. Damit ist der Pointer in der main() Funktion eigentlich ungültig. Zufällig steht da jetzt immer noch die 2 aus deiner Funktion. Es könnte aber auch schon etwas anderes dort stehen.
-
Kannst du mir vielleicht erklären wie genau ich den Pointer überschrieben hab? Ich kann das irgendwie nicht nachvollziehen.
So sieht das für mich gerade aus(Pfeile symbolisieren nen Pointer)
pPointer2 vor Zeile 8:
->->&pPointer1 ( = ->->&Zahl2 )
nach Zeile 8:
->->&Zahl
pPointer1 die ganze Zeit:
->&Zahl2
Wo liegt mein Denkfehler?
-
Vor Zeile 8:
pointer2 -> pPointer1 -> Zahl2
Nach Zeile 8:
pointer 2 -> pPointer1 -> Zahl
Was du verstehen musst ist, dass dein 'int **pointer2' ein pointer auf ein pointer auf ein int ist und durch den funktionsaufruf mit foo(&pPointer1); zeigt dieser nunmal auf pPointer1.
Zeile 8 ändert nun das ziel von pointer2 (*pointer2 = pointer2 dereferenziert) was nunmal pPointer1 ist auf die Adresse von Zahl (&Zahl = Adresse von)
-
Vielen Dank, jetzt hats klick gemacht

-
Und noch was, was du gleich verstehen solltest:
Lifecycles:
Das Deine Ausgabe 2 anzeigt, ist quasi nur "Glück".
void foo(int **pPointer2) { int Zahl=2; *pPointer2=&Zahl; }int Zahl=2; erzeugt dir eine lokale Variable aufn Stack
*pPointer2=&Zahl; Du schreibst die Adresse der Variablen an die Adresse die dir dein Pointer Paramater gibt. AKA du gibts sie nach außen.
} Du verläßt den scope der funktion, aka alle lokalen variablen der funktion werden ungültig, freigegeben ... d.h. die runtime kann den Speicher weiterverwenden / überschreiben ....Wie gasagt, das da "noch" 2 drinne steht ist Glück. Wenn dein programm mehr machen würde, würde die runtime den speicher wieder verwenden und dann könnt irgendwas drinnstehen -> undefiniertes verhalten. Und sowas lieben Entwickler

Für Lern- und Verständnisszwecke ist diese Pointer-Orgie ganz ok

Aber "normal" arbeitest in C++ mehr mit Referenzen und "verpackte" pointer.
Nur wenn C-Api's bedienen musst, musst dich oft mit pointer of pointer auseinandersetzen.Ciao ...
-
Danke,ja das Beispiel ist schlecht gewählt. In meinem richtigen Programm zeigt der Pointer auf den Heap. Habs hier nur mal so zur Vereinfachung gemacht.
Ich weiß jetzt auch was ich genau nicht verstanden habe:
Ich habe immer gedacht wenn ich einen Doppelpointer definiere, dann ist dieser an sich schon ein zweiteiliges Gebilde(also Pointer auf Pointer). Aber er ist tatsächlich nur ein Teil dieses Gebilde, nämlich der erste Pointer. Danach muss eben noch der zweite Pointer (pPointer1) kommen.
Deswegen war ich so verwirtt, dass ich über den Dereferenzierungsoperator auf pPointer1 zugreife.
-
RHBaum schrieb:
Wie gasagt, das da "noch" 2 drinne steht ist Glück. Wenn dein programm mehr machen würde, würde die runtime den speicher wieder verwenden und dann könnt irgendwas drinnstehen -> undefiniertes verhalten. Und sowas lieben Entwickler

Nicht nur das. Schon wenn man nur foo alleine betrachtet ist schon klar, dass jedweder spätere Zugriff über den übergebenen Zeiger auf die lokale Variable undefiniert sein wird. Ein cleverer Compiler kann und wird das sehen und bei entsprechenden Optimierungseinstellungen den ganzen Inhalt der Funktion weg optimieren. Das einzig beobachtbare Verhalten der Funktion wäre schließlich solch ein undefinierter Zugriff, sofern er denn erfolgt. Nichts zu tun ist eine besonders effiziente Art, sich undefiniert zu verhalten.
Es besteht dann also nicht nur die Gefahr, dass die 2 zwischendurch überschrieben wird: Die 2 ist überhaupt nie da!
(Und natürlich würde Arcoths selbstentwickelter Compiler an der Stelle Code zur Festplattenformatierung einfügen, bloß um zu zeigen, dass dies auch konformes Verhalten ist
)