Nur die *
, []
und ()
Betreiber haben keine Bedeutung in Erklärungen (C ++ fügt hinzu &
, aber wir gehen nicht in das hier).
In der Erklärung
int *p;
Die int
-ness von p
wird vom Typbezeichner angegeben int
, während die Zeigerzahl von p
vom Deklarator angegeben wird *p
.
Der Typ von p
ist "Zeiger auf int
"; Dieser Typ wird vollständig durch die Kombination des Typspezifizierers int
und des Deklarators angegeben *p
.
In einer Deklaration führt der Deklarator den Namen der deklarierten Sache ( p
) zusammen mit zusätzlichen Typinformationen ein, die nicht vom Typspezifizierer angegeben werden ("Zeiger auf"):
T v; // v is a single object of type T, for any type T
T *p; // p is a pointer to T, for any type T
T a[N]; // a is an N-element array of T, for any type T
T f(); // f is a function returning T, for any type T
Dies ist wichtig - Zeiger, Array und Funktion werden als Teil des Deklarators angegeben, nicht als Typspezifizierer 1 . Wenn du schreibst
int* a, b, c;
es wird analysiert als
int (*a), b, c;
so a
wird nur als Zeiger auf deklariert int
; b
und c
werden als reguläre int
s deklariert .
Die *
, []
und ()
Betreiber können kombiniert werden , um beliebig komplexe Typen zu erstellen:
T *a[N]; // a is an N-element array of pointers to T
T (*a)[N]; // a is a pointer to an N-element array of T
T *(*f[N])(); // f is an N-element array of pointers to functions
// returning pointer to T
T *(*(*(*f)[N])())[M] // f is a pointer to an N-element array of pointers
// to functions returning pointers to M-element
// arrays of pointers to T
Beachten Sie, dass *
, []
und ()
befolgen Sie in Deklarationen dieselben Vorrangregeln wie in Ausdrücken. *a[N]
wird wie *(a[N])
in Deklarationen und Ausdrücken analysiert .
Das wirklich Wichtige dabei ist, dass die Form einer Deklaration mit der Form des Ausdrucks im Code übereinstimmt. Zurück zu unserem ursprünglichen Beispiel haben wir einen Zeiger auf eine Ganzzahl namens p
. Wenn wir diesen ganzzahligen Wert abrufen möchten, verwenden wir den *
Operator zum Dereferenzieren p
wie folgt :
x = *p;
Der Typ des Ausdrucks *p
ist int
, der sich aus der Deklaration ergibt
int *p;
Wenn wir ein Array von Zeigern auf haben double
und einen bestimmten Wert abrufen möchten, indizieren wir das Array und dereferenzieren das Ergebnis:
y = *ap[i];
Auch die Art des Ausdrucks *ap[i]
ist double
, der aus der Erklärung folgt
double *ap[N];
Warum also nicht ++
eine Rolle spielen , in einer Erklärung , wie *
, []
oder ()
? Oder irgendein anderer Betreiber wie +
oder ->
oder &&
?
Nun, im Grunde, weil die Sprachdefinition dies sagt. Er setzt nur beiseite *
, []
und ()
jede Rolle in einer Erklärung zu spielen, da Sie angeben , Zeiger, Array in der Lage sein müssen, und Funktionstypen. Es gibt keinen separaten "Inkrement-this" -Typ, sodass Sie nicht ++
Teil einer Deklaration sein müssen. Es gibt keine „bitweise diese“ Art, so dass keine Notwendigkeit für einstellige &
, |
, ^
, oder ~
entweder Teil einer Erklärung zu sein. Für Typen, die den .
Elementauswahloperator verwenden, verwenden wir die Tags struct
und union
in der Deklaration. Für Typen, die den ->
Operator verwenden, verwenden wir die Tags struct
und union
in Verbindung mit dem *
Operator im Deklarator.
- Natürlich können Sie typedef Namen für Zeiger-, Array- und Funktionstypen erstellen, wie z
typedef int *iptr;
iptr a,b,c; // all three of a, b, and c are pointers to int
Aber auch hier ist es der Deklarator *iptr
, der den Zeiger des Typedef-Namens angibt.
void move(int *units) { ... }
ist es ein Indirektionsoperator. Als Teil des Typs betrachtet, kann es auch geschrieben werdenvoid move(int* units) { ... }
, obwohl ich den früheren Stil bevorzuge. Sie lesen beide als "int Zeiger". Siehe auch stackoverflow.com/a/8911253