Verständnisproblem mit Pointern
-
Hallo, ich habe mir heute den ganzen Tag das thema Pointer "angetan" und habe noch gewisse verständnisprobleme. Ich habe folgendes Programm geschrieben. Ich bitte darum mir zu helfen, wie ich im Kopf das verhalten der Pointer verarbeiten muss. Ich habe in den Kommentaren des Programm geschrieben, was ich an den Stellen denke. Übersetz ich das richtig?
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> void tauschewerte(int *zeiger1, int *zeiger2){ // Die Werte der Adressen auf die zeiger1 und zeiger2 zeigen werden übergeben! int hilf; hilf = *zeiger1; //Der Wert der Adresse auf den zeiger1 zeigt wird an hilf übergeben. *zeiger1 = *zeiger2; //Der Wert der Adresse auf den zeiger2 zeigt wird an den Wert der Adresse auf den Zeiger1 zeigt übergeben. *zeiger2 = hilf; //Der Wert von hilf wird an die Adresse auf die zeiger2 zeigt übergeben. } main(void){ int x=1, y=5; tauschewerte(&x,&y); //Die Adressen von x und y werden übergeben, //damit die Zeiger in der Funktion wissen, auf welche Adressen sie zeigen! printf("\nx=%i\ny=%i\n",x,y); }
Was passiert, wenn ich in der Funktion die sterne vor *zeiger1 und *zeiger2 weglasse? Wird dann die Adresse als Wert übergeben ?
-
hilf = *zeiger1; //Der Wert an der Adresse auf den zeiger1 zeigt wird an hilf zugewiesen. *zeiger1 = *zeiger2; //Der Wert an der Adresse auf den zeiger2 zeigt wird an der Adresse auf den zeiger1 zeigt abgelegt. *zeiger2 = hilf; //Der Wert von hilf wird an der Adresse auf die zeiger2 zeigt abgelegt.
zeiger1 = zeiger2; // Ist (wie) eine Variablenzuweisung. zeiger1 zeigt jetzt auf die selbe Stelle wie zeiger2.
-
Ich weiss nich, ich merk mir das einfach so:
Pointer sind auch nur stinknormale Variablen, da ist absolut nichts besonderes dran. Interpretiert werden sie halt nicht als Zahlen oder Buchstaben oder sonstwas, sondern eben als Adressen im Speicherbereich. Mehr muss man eigentlich nicht wissen.
(Ich fürchte das ist nich besonders hilfreich)
MfG
-
void main(){ unsigned int x,y; int *zeiger1; int *zeiger2; x=1; y=5; x=zeiger1; //Die Sternchen sind ja nun weg ... y=zeiger2;
was passiert denn nun? Wird die adresse (z.b. 9998987) von zeiger 1 in x als wert gespeichert?
würde ich jetz quasi printf("%i",x); eingeben, spuckt er denn die adresse von zeiger 1 als Wert einfach aus?
-
Nein, nicht die Adresse von zeiger1, sondern die Adresse die zeiger1 speichert.
zeiger1 ist eine Variable
int x, *zeiger; x = (int) zeiger
bedeutet doch nich weiter als das der Wert den zeiger speichert als int zu interpretieren ist.
Oder meintest du was anderes?
-
Hi,
also
int * zeiger; int x =(int) zeiger; // hier wird die Addresse auf den zeiger zeigt in ein //signed integer konvertiert und als wert in der variable x gespeichert..
grüße
-
ich versteh einfach bis heute nicht was mit zeigern passiert, wenn im c-programm vor ihnen kein stern mehr ist und ihre namen dennoch auftauchen ...
-
Ja nix. Dann sind es normale Variablen die irgend ein Wert haben (und C weiß dass das irgendwelche Adressen sind, deswegen kann man auch * dranschreiben was dann für C heisst "geh dorthin und hol Wert").
-
zeusosc schrieb:
Hi,
also
int * zeiger=0x01; int x =(int) zeiger; // hier wird die Addresse auf den zeiger zeigt in ein //unsigned integer konvertiert und als wert in der variable x gespeichert..
"int" ist IMHO immer signed. Und einen Zeiger sollte man nicht in einen "int" konvertieren*, denn Adressen können breiter sein (also mehr Bits zum speichern benötigen) als ein "int". Am ehesten ist der Typ ptrdiff_t dazu geeignet.
Sollte eine Compiler-Warnung geben.
-
Vielleicht hilft Dir folgendes:
(Variiert aber von Kompiler zu Kompiler,
daher das nur als Lehrmittel zu verstehen)Es gibt zwei Arten von Speicher, einmal der Stack und der Heap.
Der Stack ist der "Code" und "Daten(segment)" Speicher, der Heap
ist zumeistens der RAM.Wenn du eine Variable in einer Funktion definierst, also
void foo(void){ int x=0; //...
Wird dieser nicht wirklich IN der Funktion vorhanden sein. Der Kompiler schafft sich ein bisschen platz auf dem Stack. Und in diesem Platz wird der Wert 0 gespeichert.
Konkret: x ist ein platzhalter für eine Addresse im Datensegment, z.B. Addresse der Funktion - 32 bit (z.B. 0x11111111-0x01=0x11111110,.. ist ja ein 32 bit system... d.h. ein schritt im Offset bedeutet -32 bit)
Also im prinzip auch schon ein Zeiger auf eine Addresse VOR dem Funktionskopf (oder woanders auf m stack)
Definierst du nun Zwei variablen:
void foo(void){ int x=0; int * zeiger; //...
So liegt der Wert der x Variablen bei: Addresse der Funktion - 64 bit
Und die des Zeigers: Addresse der Funktion - 32 bit
Dabei spielt es noch keine Rolle ob die Variable zeiger ein Zeiger ist oder nicht.Macht man aber folgendes:
zeiger=&x;
Nun interpretiert der Kompiler die Variable zeiger immer noch als Variable,
dieser legt auf der Addresse: Addresse der Funktion -32 bit, den Wert:
Addresse der Funktion - 64 bit.Nun damit die Wirkung des Zeigers voll entfaltet werden kann:
int foo(void){ int x=0; int * zeiger; zeiger=&x; *zeiger=1; //das ist neu return x; }
Also hier interpretiert der Kompiler nun den Wert der Variablen Zeiger als eine
Addresse auf der dieser Arbeiten kann. D.h. die 1 wird nun in dem Speicher der
Variablen x abgelegt. Denn die Addresse von x ist ja der Wert der Variablen zeiger.
-
zeusosc schrieb:
Es gibt zwei Arten von Speicher, einmal der Stack und der Heap.
Der Stack ist der "Code" und "Daten(segment)" Speicher, der Heap
ist zumeistens der RAM.Der Stack ist auch RAM und wird nach dem LIFO-Prinzip* verwaltet.
Auf dem Stack sind Rücksprungadressen und (oft, aber nicht zwingend) Funktionsargumente und funktionslokale Variablen. Code liegt normalerweise in einem schreibgeschützten Bereich, muß also nicht zwangsläufig im RAM sein. Und der Heap ist das, was mit malloc(), realloc() und free() bedient wird.
-
int foo(void){ int x=0; int * zeiger; zeiger=&x; *zeiger=1 return x; }
seh ich das richtig das ich zeiger halt nur ohne stern sehe, wenn sie die adresse einer variablen zugeordnet bekommen, weil es ansonsten keinen sinn macht? So wie oben in dem code gegeben?
ich werde niemals etwas findet wie:
int * zeiger; zeiger=x;
oder?
-
Ich glaube ja dass das alles viel zu kompliziert ist. Bessere finde ich erstmal überhaupt nicht zwischen Variablen und Zeigern zu unterscheiden. Es gibt einfach nur Variablen, ein kleiner definierter Speicherbereich irgendwo egal ob Heap oder Stack. Eine Variable hat demzufolge eine Adresse und einen Wert (auch Zeiger).
Was man mit einer Variablen anstellen kann, also die Menge an Operationen die einem zur Verfügung stehen, bestimmt der Typ. Typen könnte man prinzipell auch weglassen. Das ist nur eine Interpretation der Daten.
Nen Zeiger ist also ne Variable vom Type Zeiger (mal so gesprochen). Folglich hat es Sinn den *-Operator zu definieren. Der referenziert nun das Objekt was sich an der Adresse findet, die der Zeiger als Variable speichert.
Kann es sein dass das Thema nur immer wieder Probleme bereitet weil fast jedes Buch das Thema als schwer ankündigt? Man somit falsch vorkonditioniert wird.
Auch versteh ich das vllt die Trennung von Typ und Zeiger bei solchen Deklarationen irreführend ist.
int x, *p;
der Typ von p ist für mich immer int* und die Variable heisst p.
(Edit: Natürlich kann man auch sagen p einmal derefernziert ist vom Typ int, mir ist das klar)Wenn man an anderer Stelle sowas macht.
x = *p;
dann ist das * hier ein unitärer Operator hat nix mit dem * oben in der Deklaration zu tun. Dieser unitäre Operator * hier liefert nun einfach den Wert des Objekts zurück, das sich an der Adresse befindet die in p gespeichert ist (und wird hier als int interpretiert weil p vom Typ int* ist).
Ich finde wenn man da mit dieser Denkweise ran geht ist das einfach zu verstehen und man hat auch keine Probleme mit z.B:
int****************** p;
-
Rammsteiner schrieb:
int foo(void){ int x=0; int * zeiger; zeiger=&x; *zeiger=1 return x; }
seh ich das richtig das ich zeiger halt nur ohne stern sehe, wenn sie die adresse einer variablen zugeordnet bekommen, weil es ansonsten keinen sinn macht? So wie oben in dem code gegeben?
ich werde niemals etwas findet wie:
int * zeiger; zeiger=x;
oder?
Japp weil genau das ihre Aufgabe ist. Adressen speichern.
-
also nochmal zusammenfassend.
Pointer sind variablen denen speicheradressen zugeordnet werden. Sie können keine Werte aufnehmen sondern nur auf die Werte zeigen die an dieser adresse stehen.
Ich benutze Pointer um beispielsweise mit hilfe einer Funktion mehrere Werte zurückzugeben, da eine Funktion ja bekanntlich nur einen Wert zurückliefern kann.
Funktionen, die variablen übergeben bekommen, bekommen eine kopie des wertes übergeben und arbeiten mit dieser kopie. Das nennt man dann**
call by value
**. Diese Kopie hat keinen Einfluss auf den Oirginalwert der Variablen.Funktionen, die Pointer bzw Variablen die auf eine speicheradresse zeigen übergeben bekommen, arbeiten mit den echten werten die auf diesen Speicheradressen stehen. Somit können diese verändert werden. Dies nennt man dann**
call by reference
**.#include <stdio.h> void funktion(int *zeiger){ //Der Funktion wird hier gesagt, das es sich bei ihrem Übergabeparameter um einen Pointer handelt. y=*zeiger; //Hier wird der Wert auf den der Pointer zeigt y zugewiesen. } int main(){ int *zeiger; //Pointer wird deklariert und bekommt den Namen Zeiger. x=1; y=0; zeiger=&x; //Pointer bekommt die Adresse von x. Dieser Pointer zeigt nun auf die Adresse von x. void funktion(zeiger); //Die Funktion bekommt die Adresse auf die der Pointer zeigt übergeben. printf("y=%i", y); }
Die Ausgabe müsste somit sein y=1!
-
Z schrieb:
zeusosc schrieb:
Es gibt zwei Arten von Speicher, einmal der Stack und der Heap.
Der Stack ist der "Code" und "Daten(segment)" Speicher, der Heap
ist zumeistens der RAM.Der Stack ist auch RAM und wird nach dem LIFO-Prinzip* verwaltet.
Auf dem Stack sind Rücksprungadressen und (oft, aber nicht zwingend) Funktionsargumente und funktionslokale Variablen. Code liegt normalerweise in einem schreibgeschützten Bereich, muß also nicht zwangsläufig im RAM sein. Und der Heap ist das, was mit malloc(), realloc() und free() bedient wird.Danke für deine Richtigstellung, sollte ich hinschreiben x~>ESP-0x01 ?
Der Heap muss auch nicht zwangsläufig im RAM sein und das der Callstack nach
Lifo arbeitet ist mir zwar klar, aber für den lernwilligen nicht nütze.Ansonsten kann er bei interesse ja mal hier
http://www.avr-modelleisenbahn.de/atmega8/2-5-stack-pointer-atmega8.htm
nachschauen,..
http://en.wikipedia.org/wiki/Call_stackgrüße
-
Nicht ganz,.. so müsste es sein...
#include <stdio.h> void funktion(int *zeiger, int &y){ //Der Funktion wird hier gesagt, das es sich bei ihrem Übergabeparameter um einen Pointer handelt. y=*zeiger; //Hier wird der Wert auf den der Pointer zeigt y zugewiesen. } int main(){ int *zeiger; //Pointer wird deklariert und bekommt den Namen Zeiger. x=1; y=0; zeiger=&x; //Pointer bekommt die Adresse von x. Dieser Pointer zeigt nun auf die Adresse von x. void funktion(zeiger,y); //Die Funktion bekommt die Adresse auf die der Pointer zeigt übergeben. printf("y=%i", y); }
-
Rammsteiner schrieb:
also nochmal zusammenfassend.
Pointer sind variablen denen speicheradressen zugeordnet werden. Sie können keine Werte aufnehmen sondern nur auf die Werte zeigen die an dieser adresse stehen.
Ich würde eher sagen: Sie können Werte aufnehmen, diese sind als Adressen im Speicher zu interpretieren.
Rammsteiner schrieb:
Ich benutze Pointer um beispielsweise mit hilfe einer Funktion mehrere Werte zurückzugeben, da eine Funktion ja bekanntlich nur einen Wert zurückliefern kann.
Ob das klappt hängt davon ab ob der Speicher auf den der Pointer Zeigt nach dem Funktionsaufruf weiterhin Gültigkeit hat (Thema Heap/Stack). Struct wären hier besser geeignet denke ich.
Edit: Ja, hab dich erst falsch verstanden.Rammsteiner schrieb:
Funktionen, die variablen übergeben bekommen, bekommen eine kopie des wertes übergeben und arbeiten mit dieser kopie. Das nennt man dann**
call by value
**. Diese Kopie hat keinen Einfluss auf den Oirginalwert der Variablen.Gilt auch für Pointer. Man könnte sagen Call by Reference gibt es in C nich wirklich.
Rammsteiner schrieb:
Funktionen, die Pointer bzw Variablen die auf eine speicheradresse zeigen übergeben bekommen, arbeiten mit den echten werten die auf diesen Speicheradressen stehen. Somit können diese verändert werden. Dies nennt man dann**
call by reference
**.Nein sie arbeiten auch mit der Kopie des Wertes des Pointers. Nur verbirgt sich dahinter eine Adresse. * dereferenziert also zum selben Objekt.
int x = 10; void funktion(int* zeiger) { zeiger = &x; } int main() { int y=6, *p; p = &y; funktion(p); printf("y=%d", *p); return 0; }
Ausgabe: y=6. p wird eben nicht auf x gebogen (call by value).
Rammsteiner schrieb:
#include <stdio.h> void funktion(int *zeiger){ //Der Funktion wird hier gesagt, das es sich bei ihrem Übergabeparameter um einen Pointer handelt. y=*zeiger; //Hier wird der Wert auf den der Pointer zeigt y zugewiesen. }
y ist nich deklariert. Sollte nicht kompilieren.
Rammsteiner schrieb:
int main(){ int *zeiger; //Pointer wird deklariert und bekommt den Namen Zeiger. x=1; y=0; zeiger=&x; //Pointer bekommt die Adresse von x. Dieser Pointer zeigt nun auf die Adresse von x. void funktion(zeiger); //Die Funktion bekommt die Adresse auf die der Pointer zeigt übergeben. printf("y=%i", y); }
Die Ausgabe müsste somit sein y=1!
Nein die Ausgabe ist y=0, da y in "main" nicht y in "funktion" ist.
-
Rammsteiner schrieb:
Die Ausgabe müsste somit sein y=1!
Die Ausgabe ist 0, da das y aus funktion() mit dem y aus main() gar nichts zu tun hat.
Es sei denn, x und y sind global. Du hast sie nirgends definiert.
Und in main() reicht dann
funktion(zeiger);
(ohne void davor)@zeusosc
Das ist hier C (nicht C++), darum mach mal das & vor dem y weg.
-
int x=1; int y=0; void funktion(int *zeiger){ y=*zeiger; } int main(){ int *zeiger; zeiger=&x; funktion(zeiger); printf("y=%i", y); }
Jetz müsste die die Ausgabe aber y=1 sein
...
Hmm, kann mir einer denn verraten was denn call by reference und call by value in c ist? Bitte nicht zu technisch werden. Ich muss irgendwie nur die Klausur nächsten Freitag schaffen falls eine Frage in die Richtung kommt was man darunter versteht ... Ich dachte ich habe das mit call by reference und call by value richtig verstanden so wie ich das oben egschrieben habe, aber wie es aussieht istd em nicht so ...