Ich verstehe die Ergebnisse des folgenden Codes nicht:
%Vor% Warum erzeugt die zweite Funktion printf
einen folgenden Fehler?
error: lvalue required as increment operand
Teil-1:
Array-Namen sind konstant (nicht modifizierbarer L-Wert), Sie können dem Array-Namen einen Wert hinzufügen, ihn jedoch nicht ändern.
Ausdruck a + 2
ändert nicht a
selbst, aber wenn Sie a++
ausführen, das äquivalent zu a = a + 1
ist, versuchen Sie, den Namen des Arrays --lvalue zu ändern. Der Ausdruck a++
im zweiten printf ist falsch - ein Beispiel für einen semantischen Phasenfehler. Lesen Sie folgende Sprachstandards:
6.3.2.1 L-Werte, Arrays und Funktionsbezeichner
724 Ein modifizierbarer L-Wert ist ein L-Wert ohne Array-Typ. hat keinen unvollständigen Typ, kein const-qualifiziert Typ, und wenn es eine Struktur oder Union ist, hat kein Mitglied (einschließlich, rekursiv, jedes Mitglied oder Element aller enthaltenen Aggregate oder Vereinigungen) mit einem Const-qualifizierten Typ.
729 Außer wenn es sich um den Operanden des Operators sizeof oder um den Operator unary
&
handelt, oder ist ein String-Literal, das zum Initialisieren eines Arrays verwendet wird, ein Ausdruck, der hat Typ "Array von Typ" wird in einen Ausdruck mit Typ konvertiert "Zeiger auf den Typ", der auf das Anfangselement des Arrays zeigt Objekt und ist kein lvalue .
Teil-2:
Beachten Sie, dass Array-Namen in den meisten Ausdrücken in der Adresse des ersten Elements abstürzen (lesen Sie einige Ausnahmen, bei denen Array-Name nicht in einen Zeiger auf das erste Element verfällt? geschickt beantwortet von @H 2 CO 3 ).
Wenn Sie a + 2
verwenden, ist sein Ergebnis die Adresse des dritten Elements (oder die Adresse des Elements am Index 2
) Also a + 2
ist gleich wie &a[2]
Es ist Adresse kein Wert am Index.
Um die Adresse zu drucken, verwenden Sie %p
anstelle von %d
und geben Sie die Adresse wie folgt in void*
ein:
Um den Wert zu drucken, benötigen Sie den Verteidigungsoperator *
wie folgt:
Teil-3:
Angenommen, a ist am Ort 2010 gespeichert, Ist die Ausgabe der ersten printf-Funktion 2012?
Nein, Zeigerarithmetik ist anders als Ganzzahlarithmetik. Wie wir wissen, zerfällt der Array-Name in den meisten Ausdrücken in die Adresse der Adresse des ersten Elements. Wenn Sie a + 2
verwenden, ist der Wert die Adresse des dritten Elements, das sich im Index 2
befindet. Angenommen, die int-Größe in Ihrem System beträgt 4 Byte, dann zeigt a + 2
stat auf den Standort 2018 entsprechend Ihrer Annahme, dass a
address value 2010 ist.
Um zu verstehen, lesen 10.2 Pointer und Arrays; Pointer Arithmetic und Pointer Arithmetic .
Ich denke, die erste Ausgabe hängt davon ab, wie der Integer-Typ in Ihrem Computer dargestellt wird. Wenn eine einzelne ganze Zahl 4 Bytes im Speicher belegt, sollte die Ausgabe 2018 sein, d. H. 2010 + 2 * 4. Der zweite Druck kann einen Kompilierungsfehler verursachen.
Zuerst ruft dieses Programm undefiniertes Verhalten auf und ich bin wenig entmutigt, dass bei so vielen Antworten keiner von ihnen dies erwähnt. In beiden printf
-Aufrufen ist Ihr Argument ein -Zeiger . Sie geben jedoch das Format als %d
an, das erwartet wird, und int
it sollte% p sein. Der C99-Entwurfsstandard im Abschnitt 7.19.6.1
Der fprintf Funktion auf die printf
's Abschnitt verweist für den Formatstring Absatz 9 sagt:
Wenn eine Konvertierungsspezifikation ungültig ist, ist das Verhalten nicht definiert. [...]
Zurück zu Ihrer Frage, der Ausdruck a++
erzeugt einen Fehler, weil postfix increment erfordert, dass es operand ist ein modifizierbarer lvalue ist Entwurfsstandard im Abschnitt 6.5.2.4
Postfix Inkrement- und Dekrementoperatoren Absatz 1 sagt ( Hervorhebung meins ):
Der Operand des Postfix-Inkrementierungs- oder Dekrementieroperators soll qualifiziert oder sein unqualifizierter Real- oder Zeigertyp und soll ein modifizierbarer L-Wert sein .
können wir aus Abschnitt 6.3.2.1
Werte, Arrays und Funktionsbezeichner sehen Absatz 1 sagt:
[...] Ein modifizierbarer Lvalue ist ein Lvalue ohne Array-Typ [...]
Array-Speicheradressen bleiben konstant, Sie können sie also nicht ändern. Das machen Sie in einer ++ Anweisung. Der Compiler wird also einen Fehler ausgeben.
a ist keine Variable vom Typ int, es ist ein Zeiger auf eine ganze Zahl. Um es zu drucken, müssen Sie es zuerst dereferenzieren
%Vor%Der Name des Arrays ist ein konstanter Zeiger und wird daher immer auf das 0. Element dieses Arrays zeigen. Es ist weder eine Variable, noch können wir ihr eine andere Adresse zuweisen, noch können wir sie durch Inkrementieren oder Dekrementieren verschieben. Daher
%Vor%Tags und Links c pointers post-increment