wake-up-neo.net

C Zeiger auf Array / Array von Zeigern Disambiguierung

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 Deklarationen?

446
George
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers

Der dritte ist der gleiche wie der erste.

Die allgemeine Regel lautet Operatorrangfolge . Es kann sogar noch komplexer werden, wenn Funktionszeiger ins Bild kommen.

423
Mehrdad Afshari

Verwenden Sie das von K & R vorgeschlagene Programm cdecl .

$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>

Es funktioniert auch umgekehrt.

cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
258
sigjuice

Ich weiß nicht, ob es einen offiziellen Namen hat, aber ich bezeichne ihn als Right-Left Thingy (TM).

Beginnen Sie bei der Variablen, gehen Sie dann nach rechts und links und rechts ... und so weiter.

int* arr1[8];

arr1 ist ein Array mit 8 Zeigern auf ganze Zahlen.

int (*arr2)[8];

arr2 ist ein Zeiger (die Klammer blockiert rechts-links) auf ein Array mit 8 ganzen Zahlen.

int *(arr3[8]);

arr3 ist ein Array mit 8 Zeigern auf ganze Zahlen.

Dies sollte Ihnen bei komplexen Deklarationen helfen.

124
GManNickG
int *a[4]; // Array of 4 pointers to int

int (*a)[4]; //a is a pointer to an integer array of size 4

int (*a[8])[5]; //a is an array of pointers to integer array of size 5 
25
Sunil bn

Die Antwort für die letzten beiden kann auch von der goldenen Regel in C abgezogen werden:

Erklärung folgt Gebrauch.

int (*arr2)[8];

Was passiert, wenn Sie arr2 dereferenzieren? Sie erhalten ein Array mit 8 ganzen Zahlen.

int *(arr3[8]);

Was passiert, wenn Sie ein Element aus arr3 nehmen? 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 x dereferenzieren? Sie erhalten eine Funktion, die Sie ohne Argumente aufrufen können. Was passiert, wenn Sie es anrufen? Es wird ein Zeiger auf ein Float zurückgegeben.

Die Rangfolge der Operatoren ist jedoch immer schwierig. Die Verwendung von Klammern kann jedoch auch verwirrend sein, da die Deklaration der Verwendung folgt. Zumindest sieht arr2 für mich intuitiv aus wie ein Array von 8 Zeigern auf ints, aber es ist tatsächlich umgekehrt. Nur gewöhnungsbedürftig. Grund genug, diese Erklärungen immer mit einem Kommentar zu versehen, wenn du mich fragst :)

edit: example

Ü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:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))

int *
put_off(const int newrow[2])
{
    static int mymatrix[3][2];
    static int (*rowp)[2] = mymatrix;
    int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);

    memcpy(rowp, newrow, sizeof(*rowp));
    rowp += 1;
    if (rowp == border) {
        rowp = mymatrix;
    }

    return *rowp;
}

int
main(int argc, char *argv[])
{
    int i = 0;
    int row[2] = {0, 1};
    int *rout;

    for (i = 0; i < 6; i++) {
        row[0] = i;
        row[1] += i;
        rout = put_off(row);
        printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
    }

    return 0;
}

Ausgabe:

0 (0x804a02c): [0, 0] 
 1 (0x804a034): [0, 0] 
 2 (0x804a024): [0, 1] 
 3 (0x804a02c): [1, 2] 
 4 (0x804a034): [2, 4] 
 5 (0x804a024): [3, 7]

Beachten Sie, dass sich der Wert von border nie ändert, sodass der Compiler ihn optimieren kann. Dies unterscheidet sich von dem, was Sie ursprünglich verwenden möchten: const int (*border)[3]: Dies deklariert border als Zeiger auf ein Array von 3 Ganzzahlen, die den Wert nicht ändern, solange die Variable existiert. Dieser Zeiger kann jedoch jederzeit auf ein beliebiges anderes derartiges Array gezeigt werden. Wir wollen diese Art von Verhalten stattdessen für das Argument (weil diese Funktion keine dieser ganzen Zahlen ändert). Erklärung folgt Gebrauch.

(ps .: zögern sie nicht diese probe zu verbessern!)

15
Hraban Luyat
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
5
Byron Formwalt

Als Faustregel gilt, dass rechtsunäre Operatoren (wie [], () usw.) den Vorzug vor links haben. int *(*ptr)()[]; wäre also ein Zeiger, der auf eine Funktion zeigt, die ein Array von Zeigern auf int zurückgibt (holen Sie sich die richtigen Operatoren, sobald Sie aus der Klammer kommen).

3
Luis Colorado

Hier ist eine interessante Website, die erklärt, wie komplexe Typen in C gelesen werden: http://www.unixwiz.net/techtips/reading-cdecl.html

2

So interpretiere ich es:

int *something[n];

hinweis zur Priorität: Der Array-Indexoperator ('[]') hat eine höhere Priorität als der Dereferenzierungsoperator ('*').

Hier wenden wir also das '[]' vor '*' an und machen die Anweisung äquivalent zu:

int *(something[i]);

beachten Sie, wie eine Deklaration Sinn macht: int num bedeutet, dass (num) ein (int), int *ptr oder int (*ptr) bedeutet, dass (value at ptr) ein (int) ist, was ptr ergibt ein Zeiger auf int.

Dies kann so gelesen werden, dass (Wert von (Wert am i-ten Index von etwas)) eine ganze Zahl ist. (Wert am i-ten Index von etwas) ist also ein (ganzzahliger Zeiger), der das etwas zu einem Array von ganzzahligen Zeigern macht.

In der zweiten,

int (*something)[n];

Um diese Aussage zu verstehen, müssen Sie mit folgender Tatsache vertraut sein:

anmerkung zur Zeigerdarstellung des Arrays: somethingElse [i] entspricht * (somethingElse + i)

Wenn Sie also somethingElse durch (* something) ersetzen, erhalten Sie * (* something + i), eine Ganzzahl gemäß Deklaration. Also hat (* etwas) uns ein Array gegeben, das etwas gleichwertig mit (Zeiger auf ein Array) macht.

2

Ich denke, wir können die einfache Regel verwenden ..

example int * (*ptr)()[];
start from ptr 

"ptr ist ein Zeiger auf" Nach rechts gehen ... "." Jetzt gehe nach links. " gibt einen Zeiger "go right" auf ein Array "go left" von ganzen Zahlen zurück

2
simal

Ich denke, die zweite Erklärung ist für viele verwirrend. Hier ist ein einfacher Weg, um es zu verstehen.

Lassen Sie uns ein Array von ganzen Zahlen haben, d. H. int B[8].

Lassen Sie uns auch eine Variable A haben, die auf B zeigt. Nun ist der Wert bei A B, d. H. (*A) == B. Daher zeigt A auf ein Array von ganzen Zahlen. In Ihrer Frage ist arr ähnlich wie A.

Ähnlich ist in int* (*C) [8] C ein Zeiger auf ein Array von Zeigern auf eine ganze Zahl.

0