C-Zeiger auf Array/Array von Zeigern Disambiguierung

Lesezeit: 7 Minuten

Benutzeravatar von George
George

Was ist der Unterschied zwischen den folgenden Deklarationen:

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);

Was ist die allgemeine Regel zum Verständnis komplexerer Deklarationen?

  • Hier ist ein großartiger Artikel über das Lesen komplexer Deklarationen in C: unixwiz.net/techtips/reading-cdecl.html

    – Jesper

    27. Januar 2013 um 13:00 Uhr

  • @jesper Leider ist das const und volatile Qualifikationsmerkmale, die sowohl wichtig als auch knifflig sind, fehlen in diesem Artikel.

    – kein Benutzer

    18. Mai 2017 um 15:32 Uhr

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

Der dritte ist derselbe wie der erste.

Die allgemeine Regel ist Operator Vorrang. Es kann noch viel komplexer werden, wenn Funktionszeiger ins Spiel kommen.

  • Also für 32-Bit-Systeme: int* arr[8]; /* 8×4 Bytes zugewiesen, für jeden Zeiger /int (*arr)[8]; / 4 Bytes belegt, nur ein Zeiger */

    – George

    13. Mai 2009 um 18:43 Uhr

  • Nö. int* anf[8]: 8×4 Bytes zugewiesen gesamt, 4 Bytes für jeden Zeiger. int (*arr)[8] stimmt, 4 Bytes.

    – mmx

    13. Mai 2009 um 18:49 Uhr

  • Ich hätte nochmal lesen sollen, was ich geschrieben habe. Ich meinte 4 für jeden Zeiger. Danke für die Hilfe!

    – George

    13. Mai 2009 um 18:59 Uhr

  • Der Grund dafür, dass der erste derselbe ist wie der letzte, ist, dass es immer erlaubt ist, Deklaratoren in Klammern zu setzen. P[N] ist ein Array-Deklarator. P(….) ist ein Funktionsdeklarator und *P ist ein Zeigerdeklarator. Im Folgenden ist also alles so wie ohne Klammern (bis auf das “()” der Funktionen): int (((*p))); void ((g(void))); int *(a[1]); ungültig (*(p())).

    – Johannes Schaub – litb

    13. Mai 2009 um 20:21 Uhr

  • Gut gemacht in deiner Erklärung. Eine ausführliche Referenz zu Vorrang und Assoziativität von Operatoren finden Sie auf Seite 53 von The C Programming Language (ANSI C zweite Ausgabe) von Brian Kernighan und Dennis Ritchie. Die Betreiber ( ) [ ] assoziieren von links nach rechts und haben eine höhere Priorität als * also lesen int* arr[8] als Array der Größe 8, wobei jedes Element auf ein int und zeigt int (*arr)[8] als Zeiger auf ein Array der Größe 8, das ganze Zahlen enthält

    – Matschig

    23. September 2017 um 14:03 Uhr


Benutzeravatar von sigjuice
Sigisaft

Verwenden Sie die cdekl 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 )

  • @ankii Die meisten Linux-Distributionen sollten ein Paket haben. Sie könnten auch Ihre eigene Binärdatei erstellen.

    – Sigissaft

    15. Oktober 2019 um 17:05 Uhr

  • ah sorry, dass ich es nicht erwähnt habe, macOS hier. Mal sehen, ob verfügbar, sonst ist die Website auch in Ordnung. ^^ Danke, dass du mich darüber informiert hast. Fühle dich frei, NLN zu melden.

    Benutzer10063119

    15. Oktober 2019 um 17:06 Uhr


  • @ankii Sie können von Homebrew (und vielleicht MacPorts?) Installieren. Wenn diese nicht nach Ihrem Geschmack sind, ist es trivial, Ihre eigenen über den Github-Link oben rechts auf cdecl.org zu erstellen (ich habe ihn gerade auf macOS Mojave erstellt). Kopieren Sie dann einfach die cdecl-Binärdatei in Ihren PATH. Ich empfehle $PATH/bin, weil es nicht nötig ist, root in etwas so einfaches wie dieses einzubeziehen.

    – Sigissaft

    15. Oktober 2019 um 17:18 Uhr

  • Oh hatte den kleinen Absatz über die Installation in der Readme-Datei nicht gelesen. nur einige Befehle und Flags für den Umgang mit Abhängigkeiten. Installiert mit brew. 🙂

    Benutzer10063119

    15. Oktober 2019 um 17:35 Uhr

Benutzeravatar von GManNickG
GManNickG

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.

int* arr1[8];

arr1 ist ein Array von 8 Zeigern auf ganze Zahlen.

int (*arr2)[8];

arr2 ist ein Zeiger (der Klammerblock rechts-links) auf ein Array von 8 ganzen Zahlen.

int *(arr3[8]);

arr3 ist ein Array von 8 Zeigern auf ganze Zahlen.

Dies sollte Ihnen bei komplexen Deklarationen helfen.

  • Ich habe gehört, dass es unter dem Namen “The Spiral Rule” bezeichnet wird, der gefunden werden kann hier.

    – fourisch

    27. Mai 2013 um 3:04 Uhr

  • @InkBlend: Die Spiralregel unterscheidet sich von Rechts-Links-Regel. Ersteres versagt in Fällen wie int *a[][10] während letzteres gelingt.

    – legends2k

    9. Oktober 2013 um 13:51 Uhr


  • Wie InkBlend und legends2k sagten, ist dies eine Spiralregel, die komplexer ist und nicht in allen Fällen funktioniert, daher gibt es keinen Grund, sie zu verwenden.

    – kotlomoi

    25. September 2014 um 18:29 Uhr

  • Vergessen Sie nicht die Assoziativität von links nach rechts ( ) [ ] und von rechts nach links * &

    – Matschig

    23. September 2017 um 14:10 Uhr

  • @legends2k: Was ist die Deklarationsanzeige für int *a[][10]

    – Bestienjunge

    21. November 2018 um 4:37 Uhr

Benutzeravatar von Sunil bn
Sunil Mrd

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 

Die Antwort für die letzten beiden lässt sich auch aus der goldenen Regel in C ableiten:

Die Deklaration folgt der Verwendung.

int (*arr2)[8];

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

int *(arr3[8]);

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

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 anrufen? Es wird einen Zeiger auf a zurückgeben float.

Der Vorrang von Operatoren ist jedoch immer schwierig. Die Verwendung von Klammern kann jedoch auch verwirrend sein, da die Deklaration auf die Verwendung folgt. Zumindest für mich intuitiv arr2 sieht aus wie ein Array von 8 Zeigern auf ints, aber es ist tatsächlich umgekehrt. Nur etwas gewöhnungsbedürftig. Grund genug, diese Erklärungen immer zu kommentieren, 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;
}

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 dies optimieren kann. Dies unterscheidet sich von dem, was Sie ursprünglich verwenden möchten: const int (*border)[3]: Das deklariert den Rand 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 solches Array zeigen. Wir wollen stattdessen diese Art von Verhalten für das Argument (weil diese Funktion keine dieser ganzen Zahlen ändert). Die Deklaration folgt der Verwendung.

(ps: Fühlen Sie sich frei, dieses Beispiel zu verbessern!)

Benutzeravatar von Byron Formwalt
Byron Formwalt

typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];

Benutzeravatar von Luis Colorado
Luis Colorado

Als Faustregel gilt, dass rechte unäre Operatoren (wie [], (), etc) haben Vorrang vor linken. So, int *(*ptr)()[]; wäre 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)

  • Das stimmt, ist aber auch illegal. Sie können keine Funktion haben, die ein Array zurückgibt. Ich habe versucht und das bekommen: 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

    – alx

    24. Februar 2019 um 1:48 Uhr

  • Der Compiler gibt diesen Fehler aus, weil er die Funktion als Rückgabe eines Arrays interpretiert, wie es die korrekte Interpretation der Vorrangregel besagt. Es ist als Erklärung rechtswidrig, aber die rechtliche Erklärung int *(*ptr)(); erlaubt einen Ausdruck wie p()[3] (oder (*p)()[3]) später verwendet werden.

    – Luis Colorado

    25. Februar 2019 um 19:39 Uhr


  • Ok, wenn ich es verstehe, sprechen Sie davon, eine Funktion zu erstellen, die einen Zeiger auf das erste Element eines Arrays (nicht ein Array selbst) zurückgibt, und diese Funktion später so zu verwenden, als ob sie ein Array zurückgeben würde? Interessante Idee. Ich werde es versuchen. int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); } und nenne es so: foo(arr)[4]; was enthalten soll arr[2][4]Rechts?

    – alx

    26. Februar 2019 um 11:35 Uhr


  • richtig… aber du hattest auch recht, und die Deklaration war rechtswidrig. 🙂

    – Luis Colorado

    27. Februar 2019 um 4:53 Uhr

1427930cookie-checkC-Zeiger auf Array/Array von Zeigern Disambiguierung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy