Fragen bezüglich Aufgabe zu Pointer und Adressen[gelöst]
-
Hallo, ich befinde mich momentan in der Prüfungsvorbereitung zu einer C++ Klausur, es geht darum, Quelltexte zu verstehen und dies dadurch zu zeigen, die korrekten Bildschirmausgaben bzw. Inhalte von Variablen angeben zu können.
Nun bin ich auf folgende Aufgabe gestoßen und habe ein Problem beim Nachvollziehen, ich hab sie mehrfach durch den Compiler laufen lassen und schrittweise die Veränderungen beobachtet, doch ab der 5. Zuweisung komme ich nicht wirklich weiter und bitte deshalb euch um Rat.
Aufgabenstellung: Bestimmen Sie den Wert für jede Variable (s.u.), nachdem folgende Code-Fragemente ausgeführt wurden. Folgende Annahmen sollen gelten:
- Eine Integer-Zahl belegt 4 Bytes.
- Die Variable m wird unter der Adresse 0x3fffd00 im Hauptspeicher gespeichert.int m = 44; int *p = &m; int &r = m; int n = (*p)++; int *q = p - 1; r = --(*p) + 1; ++*q;Gesucht sind:
Inhalt Variable n:
Inhalt Variable &m:
Inhalt Variable *p:
Inhalt Variable r:
Inhalt Variable *q:Nun zu meinem Lösungsvorschlag:
Inhalt Variable n: 44 - Da in der Zuweisung int n = (*p)++; (*p) postinkrementiert wird und somit n den "alten" Wert zugewiesen bekommt.
Inhalt Variable &m: - Die Adresse aus der Aufgabenstellung.
Inhalt Variable *p: - 45 da (p) postinkrementiert wurde.
Inhalt Variable r: - Hier bin ich mir unsicher ob die Zuweisung mit r überhaupt Auswirkungen hat
Inhalt Variable *q: - Hier bin ich mir unsicher, ob ich überhaupt eine Aussage über den Inhalt von Variable *q treffen kann.Für Tipps, Ratschläge und Erklärungen schon mal ein Dankeschön und ein schönes Wochenende

-
Der Tricky Teil des ganzen ist diese Zeile:
r = --(*p) + 1;meditiere darueber nochmal ordentlich. Und denke daran, dass r eine Referenz auf m ist.
Die Zeile
++*q;
ist auch fies. Denk hierbei ein die Operator Precedence: http://en.cppreference.com/w/cpp/language/operator_precedence
-
Raw schrieb:
Aufgabenstellung: Bestimmen Sie den Wert für jede Variable (s.u.), nachdem folgende Code-Fragemente ausgeführt wurden. Folgende Annahmen sollen gelten:
- Eine Integer-Zahl belegt 4 Bytes.
- Die Variable m wird unter der Adresse 0x3fffd00 im Hauptspeicher gespeichert.int m = 44; int *p = &m; int &r = m; int n = (*p)++; int *q = p - 1; r = --(*p) + 1; ++*q;Gesucht sind:
Inhalt Variable n:
Inhalt Variable &m:
Inhalt Variable *p:
Inhalt Variable r:
Inhalt Variable *q:&m, *p, *q sind keine Variablen. Die Variablen heißen m, p und q. Gefragt ist anscheinend aber jeweils nach den Werten der genannten Ausdrücke.
Inhalt Variable n: 44 - Da in der Zuweisung int n = (*p)++; (*p) postinkrementiert wird und somit n den "alten" Wert zugewiesen bekommt.
Richtig.
Inhalt Variable &m: - Die Adresse aus der Aufgabenstellung.
Der Wert des Ausdruckes &m ist die genannte Adresse, ja.
Inhalt Variable *p: - 45 da (p) postinkrementiert wurde.
*p wird am Ende auch nochmal dekrementiert.
Inhalt Variable r: - Hier bin ich mir unsicher ob die Zuweisung mit r überhaupt Auswirkungen hat
Tatsächlich hat die Zuweisung undefiniertes Verhalten, weil r und p beide auf m zeigen und somit dieselbe Speicherstelle zwischen zwei Sequenzpunkten mehrfach modifiziert wird.

Inhalt Variable *q: - Hier bin ich mir unsicher, ob ich überhaupt eine Aussage über den Inhalt von Variable *q treffen kann.
Genau, kann man nicht. Das ist wieder undefiniertes Verhalten.
Die Zeile
++*q;
ist auch fies. Denk hierbei ein die Operator PrecedenceDas ist nicht fies und hat auch nichts mit der Operator Precedence zu tun. Wenn der Geist von Dennis Ritchie aus dem Jenseits erscheint und die Operatorenrangfolge zufällig durchpermutiert hat der obige Ausdruck immer noch dieselbe Bedeutung.
-
*p wird am Ende auch nochmal dekrementiert.
Ja, an der Stelle: r = --(*p) + 1. Aber sorgt +1 nicht dafür, dass der Effekt der Dekrementierung aufgehoben wird und p den ursprünglichen Wert erlangt?
-
Wie gesagt, diese Anweisung hat undefiniertes Verhalten, weil nicht klar ist, in welcher Reihenfolge die Zuweisung an r und die Dekrementierung stattfinden. Man kann nicht sinnvoll sagen, was die Werte der Variablen danach sind. Strenggenommen sind sogar alle Aussagen über die Werte der Variablen *davor* dadurch Makulatur.
-
Danke für die Erklärung. Für den Fall dass kein UB auftritt hab ich das ganze nochmal im Compiler getestet und deine Aussage stimmt, das Ergebnis das ich angesprochen habe wird nur der Variable zugeordnet, die diesen Ausdruck enthält.
-
Raw schrieb:
Danke für die Erklärung. Für den Fall dass kein UB auftritt hab ich das ganze nochmal im Compiler getestet und deine Aussage stimmt, das Ergebnis das ich angesprochen habe wird nur der Variable zugeordnet, die diesen Ausdruck enthält.
UB tritt in jedem Fall auf, der Compiler ist nur so nett, keinen Code einzufügen, der deine Festplatte formatiert, sondern versucht etwas daraus zu machen.
Nett von dem Compiler, wäre aber in jedem Fall standardkonform.
-
Raw schrieb:
Für den Fall dass kein UB auftritt
Was soll das bedeuten?
UB ist die Situation, dass der Sprachstandard keine Aussage welcher Art auch immer über das Verhalten eines Programms macht. Das kann per Definition nicht "auftreten", insbesondere kann man ein Programm, dass undefiniertes Verhalten enthält, nicht darauf testen, ob das Verhalten undefiniert ist.Man sagt trotzdem schlampigerweise, dass UB "auftritt", meint damit aber, dass eine Situation eintritt, in der das Programm UB hat. Das ist in deinem Programm aber nicht so, das UB tritt in diesem Sinne immer auf.
-
Shade Of Mine schrieb:
Die Zeile
++*q;
ist auch fies. Denk hierbei ein die Operator Precedence: http://en.cppreference.com/w/cpp/language/operator_precedenceDie q-Sache ist auch ganz klar UB (mehrfach).
Die Initialisierung von q ist schon UB, weil man keine Zeiger auf Sachen erzeugen darf die's gar nicht gibt. (Ausgenommen der "one past last" Regel natürlich, "one before first" Regel wäre mir aber keine bekannt. Und sogar die "one past last" Regel bezieht sich soweit ich weiss nur auf Arrays.)
Aber selbst wenn man davon ausgeht dass es noch OK wäre Zeiger zu erzeugen die eine unsinnige Adresse enthalten...
Und wir davon ausgehen dass ((p - 1) + 1) wieder p ergibt, selbst wenn es vor p gar nichts gibt...Selbst dann ist
++*q;doch UB -- oder hab ich da was falsch verstanden?Wie haben hier zwei Prefix Operatoren (Rechts -> Links Assozivität!). Also wird erst
*qausgewertet. Und auf das Ergebnis von*qdann++angewendet.
Also++(*q)Und das ist ja wohl eindeutig Unsinn, da wir ein Objekt das nicht existiert ("one before m") ja wohl nicht inkrementieren können.
----
Ich denke der Ersteller dieser Übung hat sich hier selbst mehrere Eier gelegt.
Und das++*q;Ei vermutlich deswegen, weil*q++nicht das selbe ist wie(*q)++-- und ihn das zu der irrigen Annahme verleitet hat dass es bei++*qund++(*q)ähnlich wäre.
-
Vielleicht will der Aufgabenersteller darauf hinaus, dass die Variablen auf dem Stack absteigend angelegt werden, so dass q auf p zeigt. Das ist natürlich hochgradig von allen möglichen Annahmen abhängig und dürfte in der Praxis bei optimierenden Compiler praktisch nie stimmen, aber vor 25 Jahren mochte der eine oder andere manchmal so gedacht haben, und mancher vielleicht heute noch.
(Ändert alles natürlich nichts am UB.)
-
Ich glaube dass der Aufgabensteller leider - wie so viele Lehrer - nicht weiss wovon er spricht.
Worauf er hinaus will ist dann schwer zu erraten.Ob er jetzt irrerweise glaubt dass (p - 1) immer auf n zeigt, oder irrerweise glaubt dass das ++ in ++*q vor dem * ausgefürht wird ... man weiss es nicht.
-
Vielen Dank für die ganzen Erklärungen, das hat mir einiges an Kopfzerbrechen erspart, schönes Wochenende noch!
