Zeigerspiele...
-
Hallo, ich habe hier eine Übungsaufgabe meines Professors. Ich blicke aber nicht ganz durch wie da was genau funktioniert.
Es kommt raus "C ist gar nicht dumm" allerdings komme ich schon nach dem ersten printf nicht mehr mit.#include <stdio.h> char *c[] = { "he dast ga", "lllt dumm", "C i", "dar nich" }; char **cp[] = { c+3, c+2, c+1, c }; char ***cpp = cp; int main( void ) { printf( "%s", **++cpp ); printf( "%s", *--*++cpp+5 ); printf( "%s", cpp[-2][0]+2 ); printf( "%s\n", *(cpp[1]+1)+3 ); getchar(); }
-
Ich versuchs (geht scheiße zu erklären).
Zeile 1 kapierst du, sagst du. Der Stand der Dinge:
cpp Zeigt auf c+2, resp. "C i".
Na dann mal die 2. Zeile:
++cpp -> cpp zeigt auf c+1, resp "lllt dumm"
*cpp -> zeiger (NICHT cpp) zeigt auf "lllt dumm"
--zeiger -> zeigt auf "he dast ga"
*zeiger -> zeigt auf 'h', ist also "he dast ga"
zeiger +5 -> zeigt auf 's', ist also "st ga"
3. Zeile
cpp[-2] -> zeigt auf c+3
zeiger[0]+2 -> =zeiger[2], zeigt also auf 'r', ist also "r nich"
4. Zeile:
cpp[1]+1 -> =cpp[2] also c+1
*cpp+3 -> "t dumm"
-
username214 schrieb:
Es kommt raus "C ist gar nicht dumm"
aber wer sowas codet ist ziemlich dumm

-
Hallo,
um das Ganze zu verstehen bedarf es ein paar Dinge:
1. Ein Pointer p speichert eine Adresse (sowie einen Typ)
Er besitzt drei Attribute:
a) Seinen Speicherort (&p)
b) Seinen Inhalt (p)
c) Seinen indirekten Wert (*p)2. Der Name eines Array verhält sich in den meisten Kontexten wie ein Pointer auf das erste Element.
3. Pointer kann man gut verstehen, wenn mans sich das Ganze in verschiedenen Ebenen vorstellt, die über bestimmte Operatoren verbunden sind (siehe 4.)
&p, also der Speicherort eines Pointers ist auf Ebene 2.
p, also der Inhalt eines Pointers ist auf Ebene 1.
*p, also der indirekte Wert eines Pointers ist auf Ebene 0.4. Die wichtigsten Pointer-Operationen:
O1) &-Operator: Gehe eine Ebene nach oben.
O2) *-Operator: Gehe eine Ebene nach unten.
O3) ++,+: Addiere einen Offset in der aktuellen Ebene
O4) --,-: Subtrahiere einen Offset in der aktuellen Eben
O4) [x]-Operator: ist äquivalent zu *(p + x). Addiert also erst einen Offset und geht dann eine Ebene nach unten.5. Falls mehrere Operationen im selben Ausdruck stehen, müssen diese nach Priorität angewandt werden. Du brauchst also eine Operator-Vorangstabelle:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-39479.htmlDamit ist das Ganze eigentlich recht einfach:
Die einzelnen Zeichen leben auf Ebene 0.
Die Stringliterale auf Ebene 1.
Das Array c enthält Zeiger. Der Name eines Arrays verhält sich in der Regel wie ein Zeiger auf das erste Element. Also ist c auf Ebene 2.
Das Array cp auf Ebene 3.
Der Zeiger cpp ist ebenfalls ein Ebene-3-Pointer.Start:
cpp zeigt auf das erste Element von cp.**++cpp:
Auswertungsreihenfolge: ++ vor *
++cpp: Setze den Zeiger (seinen Inhalt) einen Schritt nach rechts. cpp zeigt nun auf das zweite Element von cp.
*: Gehe eine Ebene tiefer. Wir sind jetzt im Array cp an Position cp[1].
*: Gehe eine Ebene tiefer. Damit sind wir in Ebene 1 im Array c an Position c[2]. Dort steht der String "C i"--++cpp+5:
Auswertungsreihenfolge: ++ vor * vor -- vor * vor +:
++cpp: Setze den Zeiger (seinen Inhalt) einen Schritt nach rechts. cpp zeigt nun auf das dritte Element von cp.: Gehe eine Ebene tiefer. Wir sind in Ebene 2, im Array cp an Position cp[2]. In cp[2] steht die Adresse von c[1].
--: Subtrahiere 1 * sizeof(char
von der Adressse die in Position cp[2] gespeichert ist. Vorher stand dort die c[1], jetzt die von c[0].*: Gehe eine Ebene tiefer. Wir sind jetzt also in c[0]. Dort steht der String
"he dast ga".
+: Auf den Zeiger der auf "he dast ga" zeigt addieren wir 5 -> "st ga"cpp[-2][0]+2:
* Auswertungsreihenfolge: [-2] vor [0] vor + 2:
cpp[-2]: Das ist das selbe wie *(cpp - 2). Wir gehen in Ebene drei als erst zwei Schritte nach links und dann eine Ebene tiefer. cpp zeigt auf cp[2]. cpp[-2] zeigt also auf cp[0].[0]: Wir sind zur Zeit in cp[0]. Dereferenzieren und kommen damit bei c[4] an -> "dar nich".
+2: "dar nich" + 2 ergibt "r nich".
(cpp[1]+1)+3 );
* Auswertungsreihenfolge: [1] vor + vor * vor +:
cpp[1] + 1: Das bedeutet addiere eins auf das Ergebnis von cpp[1].
Das Ergebnis von cpp[1] ist cp[3] (cpp zeigt auf cp[2] -> ein Schritt nach links und einen nach unten ergibt sp[3]). Jetzt wird auf die Adresse die in cp[3] steht 1 * sizeof(char
addiert. Damit zeigt cp[3] nicht mehr auf c[0] sondern auf c[1].*: Durch die Dereferenzierung kommen wir bei c[1] an -> "lllt dumm".
+3: "lllt dumm" + 3 = "t dumm"Fertig.
-
Geniale Übungsaufgabe (aber nut für Fortgeschrittene) sollte aber mit dem Hinweis versehen sein. "So kann man´s machen, soll man aber nicht".
Eigentlich eine tolle Idee in einem Programm einen Text zu verstecken, der nicht trivial lesbar ist. Ich glaube um das aus dem Assembler zu reengineren ist erheblicher Aufwand nötig. Außerdem muss man auch erst einmal den Sinn erkennen.
Eigentlich schon fast doppelsinning das "username214" sich das C++ Forum für die Hilfe ausgesucht hat
Ich werde mit noch etwas Zeit nehmen müßen um die Erklärungen von NESS und HumeSikkins durchzuarbeiten.
-
Wer dieses Pointer-Video noch nicht kennt, sollte es sich mal rein ziehen:
Binky Pointer Fun Video
http://www.cs.stanford.edu/cslibrary/PointerFunCpp.avi (300 x 320, 14 Megabytes)
http://www.cs.stanford.edu/cslibrary/PointerFunCppBig.avi (640 x 480, 34 Megabytes)Vielleicht versteht man es dann besser?

-
Artchi schrieb:
Wer dieses Pointer-Video noch nicht kennt, sollte es sich mal rein ziehen:
Binky Pointer Fun Video
http://www.cs.stanford.edu/cslibrary/PointerFunCpp.avi (300 x 320, 14 Megabytes)
http://www.cs.stanford.edu/cslibrary/PointerFunCppBig.avi (640 x 480, 34 Megabytes)Vielleicht versteht man es dann besser?

LOL
