Was ist der Unterschied zwischen den folgenden Erklärungen:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
Was ist die allgemeine Regel für das Verständnis komplexerer Erklärungen?
c
arrays
pointers
variable-declaration
George
quelle
quelle
const
undvolatile
Qualifikation , die wichtig und heikel ist, wird in diesem Artikel fehlt.Antworten:
Der dritte ist der gleiche wie der erste.
Die allgemeine Regel ist die Priorität des Operators . Es kann noch viel komplexer werden, wenn Funktionszeiger ins Bild kommen.
quelle
( ) [ ]
assoziieren von links nach rechts und haben eine höhere Priorität als*
das, wasint* arr[8]
als Array der Größe 8 gelesen wird, wobei jedes Element auf ein int zeigt, undint (*arr)[8]
als Zeiger auf ein Array der Größe 8, das ganze Zahlen enthältVerwenden Sie das von K & R vorgeschlagene Programm cdecl .
Es funktioniert auch umgekehrt.
quelle
Ich weiß nicht, ob es einen offiziellen Namen hat, aber ich nenne es das Right-Left Thingy (TM).
Beginnen Sie bei der Variablen, gehen Sie dann nach rechts und links und rechts ... und so weiter.
arr1
ist ein Array von 8 Zeigern auf Ganzzahlen.arr2
ist ein Zeiger (der Klammerblock rechts-links) auf ein Array von 8 Ganzzahlen.arr3
ist ein Array von 8 Zeigern auf Ganzzahlen.Dies sollte Ihnen bei komplexen Deklarationen helfen.
quelle
int *a[][10]
während letztere gelingt.( ) [ ]
und von rechts nach links von* &
quelle
[5]
) repräsentiert die innere Dimension. Dies bedeutet, dass dies(*a[8])
die erste Dimension und somit die äußere Darstellung des Arrays ist. Was jedes Element innerhalba
zeigt, ist ein anderes ganzzahliges Array der Größe 5.Die Antwort für die letzten beiden kann auch von der goldenen Regel in C abgezogen werden:
int (*arr2)[8];
Was passiert, wenn Sie dereferenzieren
arr2
? Sie erhalten ein Array von 8 Ganzzahlen.int *(arr3[8]);
Was passiert, wenn Sie ein Element entnehmen
arr3
? Sie erhalten einen Zeiger auf eine Ganzzahl.Dies hilft auch beim Umgang mit Zeigern auf Funktionen. Um das Beispiel von Sigjuice zu nehmen:
float *(*x)(void )
Was passiert, wenn Sie dereferenzieren
x
? Sie erhalten eine Funktion, die Sie ohne Argumente aufrufen können. Was passiert, wenn Sie es nennen? Es wird ein Zeiger auf a zurückgegebenfloat
.Die Priorität des Bedieners ist jedoch immer schwierig. Die Verwendung von Klammern kann jedoch auch verwirrend sein, da die Deklaration auf die Verwendung folgt. Zumindest
arr2
sieht es für mich intuitiv aus wie ein Array von 8 Zeigern auf Ints, aber es ist tatsächlich umgekehrt. Es ist nur gewöhnungsbedürftig. Grund genug, diesen Erklärungen immer einen Kommentar hinzuzufügen, wenn Sie mich fragen :)bearbeiten: Beispiel
Übrigens bin ich gerade auf die folgende Situation gestoßen: Eine Funktion mit einer statischen Matrix, die Zeigerarithmetik verwendet, um festzustellen, ob der Zeilenzeiger außerhalb der Grenzen liegt. Beispiel:
Ausgabe:
Beachten Sie, dass sich der Wert von border nie ändert, sodass der Compiler dies optimieren kann. Dies unterscheidet sich von dem, was Sie ursprünglich verwenden möchten
const int (*border)[3]
:: Das deklariert border als Zeiger auf ein Array von 3 Ganzzahlen, die den Wert nicht ändern, solange die Variable vorhanden ist. Dieser Zeiger kann jedoch jederzeit auf ein anderes solches Array gerichtet sein. Wir wollen stattdessen diese Art von Verhalten für das Argument (weil diese Funktion keine dieser ganzen Zahlen ändert). Erklärung folgt Verwendung.(ps: zögern Sie nicht, dieses Beispiel zu verbessern!)
quelle
quelle
Als Faustregel gilt : rechts unäre Operatoren (wie
[]
,()
usw.) haben Vorrang vor links diejenigen. Wäreint *(*ptr)()[];
also ein Zeiger, der auf eine Funktion verweist, die ein Array von Zeigern auf int zurückgibt (holen Sie sich die richtigen Operatoren, sobald Sie aus der Klammer herauskommen können).quelle
error: ‘foo’ declared as function returning an array int foo(int arr_2[5][5])[5];
unter GCC 8 mit$ gcc -std=c11 -pedantic-errors test.c
int *(*ptr)();
ermöglicht die spätere Verwendung eines Ausdrucks wiep()[3]
(oder(*p)()[3]
).int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); }
und nenne es so:foo(arr)[4];
was soll enthaltenarr[2][4]
, oder?Ich denke, wir können die einfache Regel anwenden.
"
ptr
ist ein Zeiger auf" nach rechts gehen .. es ")" jetzt nach links gehen ist ein "(" herauskommen nach rechts gehen "()" also "auf eine Funktion, die keine Argumente akzeptiert" nach links gehen "und einen Zeiger zurückgeben" gehen " rechts "zu einem Array" gehe links "von ganzen Zahlen"quelle
)
, jetzt nach links gehen ... es ist*
"ein Zeiger auf" nach rechts gehen ... es ist)
, jetzt nach links gehen ... es ist a(
komm raus, gehe nach rechts()
so "zu einer Funktion, die keine Argumente akzeptiert" gehe nach rechts ...[]
"und gebe ein Array von" nach rechts gehen;
, also nach links gehen ...*
"Zeiger auf" nach links gehen ...int
"Ganzzahlen" zurück.Hier ist eine interessante Website, auf der erklärt wird, wie komplexe Typen in C gelesen werden: http://www.unixwiz.net/techtips/reading-cdecl.html
quelle
So interpretiere ich es:
Also, hier werden wir die Anwendung
[]
vor*
, um die Anweisung äquivalent zu machen:Dies kann gelesen werden als (Wert von (Wert am i-ten Index des Etwas)) ist eine ganze Zahl. Also (Wert am i-ten Index von etwas) ist ein (ganzzahliger Zeiger), der das Etwas zu einem Array von ganzzahligen Zeigern macht.
Im zweiten,
Um aus dieser Aussage einen Sinn zu machen, müssen Sie mit dieser Tatsache vertraut sein:
Also, ersetzt
somethingElse
mit(*something)
, bekommen wir*(*something + i)
, was eine ganze Zahl als pro - Deklaration. Geben Sie(*something)
uns also ein Array, das etwas Äquivalentes zu (Zeiger auf ein Array) macht .quelle
Ich denke, die zweite Erklärung ist für viele verwirrend. Hier ist eine einfache Möglichkeit, dies zu verstehen.
Lassen Sie uns ein Array von ganzen Zahlen haben, dh
int B[8]
.Lassen Sie uns auch eine Variable A haben, die auf B zeigt. Nun ist der Wert bei A B, dh
(*A) == B
. Daher zeigt A auf ein Array von ganzen Zahlen. In Ihrer Frage ähnelt arr A.In ähnlicher Weise ist in
int* (*C) [8]
C ein Zeiger auf ein Array von Zeigern auf eine Ganzzahl.quelle
In dieser Deklaration
arr1
befindet sich ein Array von 5 Zeigern auf Ganzzahlen. Grund: Eckige Klammern haben eine höhere Priorität als * (Dereferenzierungsoperator). Bei diesem Typ ist die Anzahl der Zeilen festgelegt (hier 5), die Anzahl der Spalten ist jedoch variabel.In dieser Deklaration
arr2
ist ein Zeiger auf ein ganzzahliges Array von 5 Elementen. Grund: Hier haben () Klammern eine höhere Priorität als []. Bei diesem Typ ist die Anzahl der Zeilen variabel, aber die Anzahl der Spalten ist fest (hier 5).quelle
Wenn der Zeiger im Zeiger auf eine Ganzzahl inkrementiert wird, wird die nächste Ganzzahl verwendet.
Wenn im Zeigerarray der Zeiger inkrementiert ist, springt er zum nächsten Array
quelle