502 Stimmen

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 Erklärungen?

469voto

mmx Punkte 400975
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 Vorrang des Operators . Es kann sogar noch viel komplexer werden, wenn Funktionszeiger ins Spiel kommen.

274voto

sigjuice Punkte 26803

Verwenden Sie die cdecl Programm, wie von K&R vorgeschlagen.

$ 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 andersherum.

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

132voto

GManNickG Punkte 476445

Ich weiß nicht, ob es einen offiziellen Namen hat, aber ich nenne es das Rechts-Links-Dingsbums(TM).

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

int* arr1[8];

arr1 ist ein Array mit 8 Zeigern auf Ganzzahlen.

int (*arr2)[8];

arr2 ist ein Zeiger (die Klammer blockiert die rechte linke Seite) auf ein Array von 8 Ganzzahlen.

int *(arr3[8]);

arr3 ist ein Array mit 8 Zeigern auf Ganzzahlen.

Dies sollte Ihnen bei komplexen Deklarationen helfen.

27voto

Sunil bn Punkte 271
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

16voto

Hraban Luyat Punkte 11

Die Antwort auf die beiden letzten Fragen lässt sich auch aus der goldenen Regel in C ableiten:

Die Erklärung erfolgt nach der Verwendung.

int (*arr2)[8];

Was passiert, wenn Sie eine Dereferenzierung arr2 ? Sie erhalten ein Array mit 8 Ganzzahlen.

int *(arr3[8]);

Was passiert, wenn Sie ein Element aus arr3 ? Sie erhalten einen Zeiger auf eine Ganzzahl.

Dies ist auch beim Umgang mit Zeigern auf Funktionen hilfreich. Um das Beispiel von sigjuice zu nehmen:

float *(*x)(void )

Was passiert, wenn Sie eine Dereferenzierung x ? Sie erhalten eine Funktion, die Sie ohne Argumente aufrufen können. Was passiert, wenn Sie sie aufrufen? Sie gibt einen Zeiger auf ein float .

Der Vorrang von Operatoren ist jedoch immer schwierig. Allerdings kann die Verwendung von Klammern auch verwirrend sein, weil die Erklärung der Verwendung folgt. Zumindest für mich, intuitiv arr2 sieht aus wie ein Array von 8 Zeigern auf ints, aber es ist eigentlich andersherum. Daran muss man sich erst einmal gewöhnen. Grund genug, diese Deklarationen immer mit einem Kommentar zu versehen, wenn Sie mich fragen :)

edit: Beispiel

Übrigens bin ich gerade über die folgende Situation gestolpert: eine Funktion, die eine statische Matrix hat und die Zeigerarithmetik verwendet, um zu sehen, 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 &lt; 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;
}

出力します。

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, so dass der Compiler dies wegoptimieren kann. Dies unterscheidet sich von dem, was Sie anfangs vielleicht verwenden möchten: const int (*border)[3] : Diese deklariert border als Zeiger auf ein Array von 3 Ganzzahlen, das seinen Wert nicht ändert, solange die Variable existiert. Dieser Zeiger kann jedoch jederzeit auf ein anderes solches Array zeigen. Wir möchten, dass sich das Argument so verhält (denn diese Funktion ändert keine dieser Ganzzahlen). Die Deklaration folgt der Verwendung.

(p.s.: Sie können dieses Beispiel gerne verbessern!)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X