Ich habe einen Zeiger und eine Variable:
%Vor%Gibt es einen Unterschied zwischen Zuweisungen
? %Vor%und
%Vor%und wie heißen sie (wie Zeigerdeklaration oder etwas)?
Achten Sie auf Typen links und rechts von =
.
&b
ist int *
, a
ist auch int *
, aber *a
ist int
.
Es ist ein wenig verwirrend, dass *
unterschiedliche Bedeutungen hat:
int *a;
- hier *
bedeutet, dass a
ein Zeiger ist;
*a = ...;
- hier *
bedeutet, dass wir nicht die in a
gespeicherte Adresse ändern, sondern den Wert, der sich an der Adresse befindet.
So a = &b
bedeutet "schreibe die Adresse von b
in a
",
aber *a = &b
bedeutet "schreibe die Adresse von b
in *a
, d. h. auf die Adresse, die in a
gespeichert ist."
Lassen Sie uns vorschlagen, dass wir diese Situation haben:
%Vor% Momentan ist a
0x0004
und *a
ist 90
.
Wenn Sie a = &b
verwenden, wird a
0x0002
und *a
wird 70
sein.
Aber wenn Sie *a = &b
machen, wird sich a nicht ändern, aber *a
, d. h. Wert an der Adresse 0x0004
, ändert sich zu 0x0002
.
Typen sind wichtig.
Im Fall von a=&b
ist die Zuweisung gültig. Sie ordnen die Adresse einer Ganzzahl (Typ: int *
) einer anderen Variablen vom Typ int *
zu, also ist dies legitim.
Im Falle von *a=&b
ist dies ein Constraint-Verstoß (für den Zuweisungsoperator, siehe Kapitel §6.5.16.1 / p1, Constraints , für Simple) Zuweisung ) und somit keine gültige C-Syntax, die nicht von einem kompilierenden Compiler kompiliert werden muss. Um eine gültige C-Syntax zu erhalten, müssen wir eine typecast erzwingen, etwa
würde es zu einer syntaktisch gültigen C-Anweisung machen, die die erforderliche Einschränkung erfüllt.
Auch danach ist das Ergebnis eine Implementierung. #note Hier versuchst du im Prinzip, die Adresse einer Ganzzahl (Typ: int *
) einer anderen Variablen vom Typ zuzuordnen int
( *a
hat den Typ int
). Die Konvertierung von einem Zeiger in eine Ganzzahl ist ein implementierungsdefiniertes Verhalten.
Zitat C11
, Kapitel §6.3.2.3, Zeiger
Jeder Zeigertyp kann in einen Integer-Typ konvertiert werden. Außer wie zuvor angegeben, die Ergebnis ist implementierungsdefiniert. Wenn das Ergebnis nicht im Integer-Typ dargestellt werden kann, Das Verhalten ist nicht definiert. [....]
[....] Und wie heißen sie?
Beide sind Zuweisungsanweisungen.
Hinweis:
Betrachtet a
zeigt bereits auf einen gültigen Speicherort. Andernfalls ruft das Deaktivieren eines ungültigen Zeigers undefiniertes Verhalten auf.
Gibt es einen Unterschied zwischen Zuweisungen
? %Vor%und
%Vor%
Ja. Im ersten Fall haben a
und &b
(Adresse von b
) beide den Typ int *
. Sie sind zuweisbar.
Im Falle von *a = &b
ist *a
vom Typ int
, während &b
vom Typ int *
ist. Bothe-Typen sind inkompatibel und der Typ &b
wird nicht explizit in den Typ *a
konvertiert. Dies ist eine Einschränkungsverletzung. Das heißt: int
-Typen können keine Zeigerobjekte halten. Die einzigen Integer-Typen, die das Zeigerobjekt halten können, sind intptr_t
und uintptr_t
.
1 Der folgende Typ bezeichnet einen signierten Integer-Typ mit der Eigenschaft, dass ein beliebiger gültiger Zeiger auf
%Vor%void
in diesen Typ konvertiert und dann in den Zeiger aufvoid
zurückkonvertiert werden kann. Das Ergebnis wird mit dem ursprünglichen Zeiger verglichen :Der folgende Typ bezeichnet einen Ganzzahl-Datentyp ohne Vorzeichen mit der Eigenschaft, dass jeder gültige Zeiger auf
%Vor%void
in diesen Typ konvertiert und dann wieder in den Zeiger aufvoid
konvertiert werden kann. Das Ergebnis wird mit dem ursprünglichen Zeiger verglichen:Diese Typen sind optional.
und wie heißen sie (wie Zeigerdeklaration oder etwas)?
Sie sind Zuweisungsanweisungen.
Ein bemerkenswerter Unterschied ist, dass die zweite Zuweisung schlecht ausgebildet ist C (wegen Einschränkung Verletzung ):
%Vor%Fehler: Zuweisung macht Integer aus Zeiger ohne eine Besetzung [-Wint-Konvertierung]
C11 §6.5.4 / 3, Darsteller:
Conversions, die Zeiger enthalten, außer wenn dies von der Einschränkungen von 6.5.16.1, soll explizit angegeben werden Cast .
Die Anforderung der expliziten Umwandlung wurde in C89 eingeführt, um eine schlechte Praxis der impliziten Konvertierung zwischen Ganzzahl- und Zeigertypen zu verbieten.
Die einzige Ausnahme von dieser Regel besteht darin, dass Sie den Zeigerwert mit 0
integer constant zuweisen können, was die Nullzeigerkonstante darstellt:
Wie alle anderen Antworten haben wir bereits auf die Variablen int *a
und int b
hingewiesen:
a = &b
ist gültig (und weist dem Zeiger b
die Adresse von a
zu, sodass *a
für den Zugriff auf b
verwendet werden kann), während *a = &b
ist eine Constraint-Verletzung, da sie versucht, die Adresse von b
der Ganzzahl zuzuordnen, auf die a
zeigt, was ohne eine explizite Umwandlung nicht erlaubt ist. Was? könnte dich verwirren, ist jedoch, dass die Variablendeklaration:
%Vor%ist gültig und macht genau dasselbe wie:
%Vor% Das ist eine sehr bequeme Abkürzung, da Sie fast immer eine Variable initialisieren möchten, sobald Sie sie deklarieren (um nur sicherzustellen, dass Sie sie nicht versehentlich versuchen, bevor sie initialisiert wird). Aber es kann verwirrend sein, wenn Sie diese Syntax zum ersten Mal sehen, da aussieht , als ob Sie &b
auf *a
zuweisen, wenn es tatsächlich a
selbst ist, das mit dem Wert initialisiert wird %Code%. Dies ist nur etwas, das Sie lernen müssen: Variableninitialisierung ist nicht das Gleiche wie normale Zuweisung, obwohl sie zum Verwechseln ähnlich aussieht.
Der erste, int a = & amp; b; kopiert die Adresse der Variablen "b" in die "a".
Die zweite, int * a = & amp; b; kopiert die Adresse der Variablen "b" in die Standort "a" zeigt auf.
Der erste ist ok, aber der zweite ruft UB auf. (Es sei denn, a
zeigt auf einen gültigen Speicher)
Lassen Sie mich zuerst den Unterschied zwischen Integer-Variablen und Zeigervariablen klären:
(1) Integer-Variable (z. B .: int b , in diesem Fall) wird zum Speichern des Werts einer Ganzzahl (der Länge 4 Byte) verwendet. Der Wert von 'b' wird an einem Speicherort gespeichert (zB 0x00000001).
(2) Eine Zeigervariable (z. B. int * a ) wird verwendet, um den Speicherplatz einer ganzzahligen Variablen zu speichern. Das heißt, in 'a' können wir die Adresse einer Integer-Variablen speichern. Der Wert, auf den eine Zeigervariable zeigt, kann durch den Operator '*' dereferenziert werden. Also hat 'a' die Adresse und '* a' den Wert, auf den der in a enthaltene Wert (Adresse) zeigt.
Beantworten Sie jetzt Ihre Frage:
Nehmen wir an, dass b = 4 und die Adresse von b (& amp; b) 0x00000001 (Hexadezimalnotation) ist.
In der ersten Typzuweisung a = & amp; b wird die Adresse der Variablen Ganzzahl b in a gespeichert (da a eine Zeigervariable ist). Jetzt hat 'a' den Wert 0x00000001 und '* a' hat 4.
In der zweiten Typzuweisung * a = & amp; b wird die Adresse der Variablen b an dem Speicherplatz gespeichert, auf den a zeigt, d. h. in der 0x00000001-Speicherstelle wird der Wert 0x00000001 selbst sein. Jetzt hat 'a' den Wert 0x00000001 und '* a' hat auch den gleichen Wert 0x00000001.
Jede Variable var
vom Typ T hat einen Speicherort im Speicher, dessen Adresse entweder vom Compiler oder von den statischen oder dynamischen Linkern zugewiesen wird. Die Adresse einiger Variablen kann mit & amp; var erhalten werden und hat den Typ pointer to T
. Wenn Sie also den Operator &
anwenden, verschachteln Sie den Typ innerhalb eines anderen Zeigers. a = & amp; b ist richtig.
Auf der anderen Seite ist *a=&b
nicht korrekt. Sie versuchen, in der Variablen * a (mit dem Typ int
) einen Zeiger auf die Basisadresse der Variablen b (vom Typ pointer to int
) zu speichern. In den Architekturen, in denen der Zeiger 64 Bits hat und int 32 Bits hat, führt dies zu einem Fehler. Auf den Architekturen hingegen, auf denen Zeiger und Int die gleiche Länge haben, ist dies möglich, wenn Sie einen Cast einfügen. Der Compiler fügt nicht automatisch eine Nötigung von int*
nach int
ein.
Tags und Links c pointers variable-assignment