[Verständnisprobleme] Zeigerarithmetik
-
Hallo Zusammen
Derzeit bin ich das Buch "C/C++ Das umfassende Lehrbuch" am Lesen.
Jedoch tauch bei mir einige Unklarheiten beim Thema Zeigerarithmetik auf.
Und zwar bei folgendem Codebeispiel:#include <iostream> using namespace std; int main() { int a; int *p = 0; cout << "p + 0 = " << p + 0 << endl; cout << "p + 1 = " << p + 1 << endl; cout << "p + 2 = " << p + 2 << endl; cout << "p + 3 = " << p + 3 << endl; return 0; }1. Es ist für mich unlogisch wieso die Adresse von p ausgegeben wird ohne Adresseoperator.
2. Wenn ich eine 1 dazu rechne, wieso wird dann der Adressbereich/Wert(?) gleich um 4 Byte erhöht. Mit einem Byte kann man ja 16 verschiedene Werte darstellen.
3. Was genau wird jetzt hier überhaupt hinzuaddiert bzw. da bei ...p + 0... ja kein Derefernzierungsoperator steht, müsste die 0 doch eigentlich zu dem Wert, auf den die Adresse zeigt, hinzuaddiert werden.Ich hoffe ihr könnt mir da weiterhelfen. Ich bin da gewissermassen etwas verwirrt.
Mit besten Grüssen
Samuel
-
Nein. Da hast du etwas grundlegend falsch an Zeiger verstanden.
Auf den Wert, auf den ein Zeiger zeigt greift man mit einem Dereferenzierungsoperator zu. Sprich mit dem *, oder ->.
int i = 2; int* pi = &i; std::cout << *pi; // gibt 2 ausUnd wenn du direkt auf eine Member zugreifen willst, kannst du mit dem
-> Operatorarbeiten.Wenn du das allerdings nicht machst, arbeitest du mit der Adresse, die den Wert referenziert.
std::cout << pi; // Die Adresse, wo i liegt.Und wenn du auf pi 1 hinzuaddierst, inkrementierst du den Zeiger, was in deinem Fall 4 Byte entspricht, also der Grösse des Datentypes, auf den er zeigt.
Du erwartest das hier:
#include <iostream> using namespace std; int main() { int a; int *p = 0; cout << "*p + 0 = " << *p + 0 << endl; cout << "*p + 1 = " << *p + 1 << endl; cout << "*p + 2 = " << *p + 2 << endl; cout << "*p + 3 = " << *p + 3 << endl; return 0; }
-
Wenn du so auf den Zeiger zugreift:
p + 1;dann erhöhst du das was im Zeiger steht. Hier ist das die Adresse der Variable die der Zeiger speichert. Dann kannst du erstmal nicht mehr auf die Variable zugreifen, da der Zeiger nun eine andere Adresse hast.
Mit der Anweisung:
*p + 1;greifst du auf das zu, was im Zeiger seine Adresse abgelegt hat. Hier ist das eine Variable, die dann um 1 inkrementiert wird.
lg, freakC++
-
drakon schrieb:
Du erwartest das hier:
#include <iostream> using namespace std; int main() { int a; int *p = 0; cout << "*p + 0 = " << *p + 0 << endl; cout << "*p + 1 = " << *p + 1 << endl; cout << "*p + 2 = " << *p + 2 << endl; cout << "*p + 3 = " << *p + 3 << endl; return 0; }halt ich für unwahrscheinlich, dass er das erwartet - evtl das hier:
#include <iostream> using namespace std; int main() { int a; int *p = &a; *p = 0; cout << "*p + 0 = " << *p + 0 << endl; cout << "*p + 1 = " << *p + 1 << endl; cout << "*p + 2 = " << *p + 2 << endl; cout << "*p + 3 = " << *p + 3 << endl; return 0; }bb
-
unskilled schrieb:
drakon schrieb:
Du erwartest das hier:
#include <iostream> using namespace std; int main() { int a; int *p = 0; cout << "*p + 0 = " << *p + 0 << endl; cout << "*p + 1 = " << *p + 1 << endl; cout << "*p + 2 = " << *p + 2 << endl; cout << "*p + 3 = " << *p + 3 << endl; return 0; }halt ich für unwahrscheinlich, dass er das erwartet - evtl das hier:
#include <iostream> using namespace std; int main() { int a; int *p = &a; *p = 0; cout << "*p + 0 = " << *p + 0 << endl; cout << "*p + 1 = " << *p + 1 << endl; cout << "*p + 2 = " << *p + 2 << endl; cout << "*p + 3 = " << *p + 3 << endl; return 0; }bb
Ich nehme an er erwartet das
#include <iostream> using namespace std; int main() { char *p = (char*)0; cout << "p + 0 = " << p + 0 << endl; cout << "p + 1 = " << p + 1 << endl; cout << "p + 2 = " << p + 2 << endl; cout << "p + 3 = " << p + 3 << endl; return 0; }
-
halt ich für unwahrscheinlich, dass er das erwartet - evtl das hier:
Hups. Den oberen Teil habe ich übersehen. So habe ich das gemeint.
-
general bacardi schrieb:
Ich nehme an er erwartet das
#include <iostream> using namespace std; int main() { char *p = (char*)0; cout << "p + 0 = " << p + 0 << endl; cout << "p + 1 = " << p + 1 << endl; cout << "p + 2 = " << p + 2 << endl; cout << "p + 3 = " << p + 3 << endl; return 0; }Das ist streng genommen auch "UB" (ruft undefiniertes Verhalten hervor). Der Standard definiert das so (sinngemäß):
Ein einzelnes Objekt, welches nicht Teil eines Arrays ist, wird bzgl Pointer-Arithmetik wie ein 1-elementiges Array behandelt.
Zeigt der Zeiger
pauf das i-te Element eines n-elementigen Arrays (oder auf das imaginäre Element hinter dem letzten, also 0<=i<=n) dann istp+kvom gleichen Zeigertyp wie p und zeigt auf das (i+k)-te Element des Arrays, FALLS 0 <= i+k <= n gilt. Sonst ist das Verhalten undefiniert.Zeigen zwei Zeiger p1 und p2 auf das i-te bzw j-te Element des selben n-elementigen Arrays (oder auf das Element hinter dem letzten, also 0 <= i,j <=n) dann ist
p1-p2vom Typ std::ptrdiff_t und hat den Wert i-j. Sonst ist das Verhalten undefiniert.Das kann man im Kapitel 5 ("Expressions") nachlesen. Am Beispiel:
int foo() { int z = 0; int* p = &z; // p zeigt auf z p+0; // OK p+1; // OK, darf man nur nicht dereferenzieren p+2; // Nicht OK (UB) p-1; // Nicht OK (UB) int array[5]; p = array; // p zeigt auf array[0] p+0; // OK p+5; // OK, darf man nur nicht dereferenzieren p+6; // Nicht OK (UB) p-1; // Nicht OK (UB) }Man darf also nicht einfach irgendeinen Wert zu einem Zeiger addieren oder irgendwelche zwei Zeiger vom gleichen Typ voneinander subtrahieren.
Gruß,
SP
-
Sebastian Pizer schrieb:
Das kann man im Kapitel 5 ("Expressions") nachlesen. Am Beispiel:
int z = 0; int* p = &z; // p zeigt auf z p+0; // OK p+1; // OK, darf man nur nicht dereferenzieren p+2; // Nicht OK (UB) p-1; // Nicht OK (UB)Laut standard ja, aber in Wirklichkeit passiert bei p+1 bis p+x oder p-x nichts schlimmes, man darf nur nicht dereferenzieren.
Ich nehme an, dass Folgendesp = (p+5)-5; *p = ...; // Dereferenzieren!auch nicht zulässig ist, obwohl p wieder seine ehemaligen Wert hat.
-
Hallo
Vielen vielen Dank für Eure Antworten.
Hat mich sehr gefreut ;).
Da ich derzeit etwas etwas Wenig habe werde ich die Beiträge bei der nächsten Gelegenheit genau durchlesen.
Vielen Dank nochmals.MfG Samuel