Question C pointeur vers tableau / tableau de désambiguïsation de pointeurs


Quelle est la différence entre les déclarations suivantes:

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

Quelle est la règle générale pour comprendre des déclarations plus complexes?


419
2018-05-13 18:35


origine


Réponses:


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

Le troisième est le même que le premier.

La règle générale est priorité de l'opérateur. Cela peut devenir encore plus complexe à mesure que des pointeurs de fonctions apparaissent.


397
2018-05-13 18:37



Utilisez le cdecl programme, tel que suggéré par K & R.

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

Cela fonctionne aussi dans l'autre sens.

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

249
2018-05-13 18:44



Je ne sais pas s'il a un nom officiel, mais je l'appelle le Thingy de droite-gauche (TM).

Commencez à la variable, puis allez à droite, et à gauche, et à droite ... et ainsi de suite.

int* arr1[8];

arr1 est un tableau de 8 pointeurs aux entiers.

int (*arr2)[8];

arr2 est un pointeur (la parenthèse bloque la droite-gauche) à un tableau de 8 entiers.

int *(arr3[8]);

arr3 est un tableau de 8 pointeurs vers des entiers.

Cela devrait vous aider avec des déclarations complexes.


117
2018-05-13 18:41



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 

24
2018-03-02 08:03



La réponse pour les deux derniers peut également être déduite de la règle d'or en C:

Déclaration suit l'utilisation.

int (*arr2)[8];

Que se passe-t-il si vous déréférencer arr2? Vous obtenez un tableau de 8 entiers.

int *(arr3[8]);

Que se passe-t-il si vous prenez un élément d'arr3? Vous obtenez un pointeur sur un entier.

Cela aide également lors de l'utilisation de pointeurs vers des fonctions. Pour prendre l'exemple de sigjuice:

float *(*x)(void )

Que se passe-t-il lorsque vous déréférencer x? Vous obtenez une fonction que vous pouvez appeler sans arguments. Qu'est-ce qui se passe quand vous l'appelez? Il retournera un pointeur sur un flotteur.

La priorité de l'opérateur est toujours délicate, cependant. Cependant, l'utilisation de parenthèses peut également être source de confusion car la déclaration suit l'utilisation. Au moins, pour moi, intuitivement arr2 ressemble à un tableau de 8 pointeurs sur ints, mais c'est en fait l'inverse. Juste prend un peu de temps pour s'y habituer. Raison suffisante pour toujours ajouter un commentaire à ces déclarations, si vous me demandez :)

éditer: exemple

Au fait, je suis juste tombé sur la situation suivante: une fonction qui a une matrice statique et qui utilise l'arithmétique de pointeur pour voir si le pointeur de ligne est hors limites. Exemple:

#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;
}

Sortie:

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

Notez que la valeur de border ne change jamais, donc le compilateur peut l'optimiser. Ceci est différent de ce que vous pourriez initialement vouloir utiliser: const int (*border)[3]: qui déclare border comme un pointeur vers un tableau de 3 entiers qui ne changeront pas de valeur tant que la variable existe. Cependant, ce pointeur peut être pointé vers n'importe quel autre tableau à tout moment. Nous voulons plutôt ce type de comportement pour l'argument (car cette fonction ne modifie aucun de ces entiers). La déclaration suit l'utilisation.

(p.s .: n'hésitez pas à améliorer cet échantillon!)


14
2017-08-14 17:51



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

5
2017-07-09 15:04



Je pense que nous pouvons utiliser la règle simple ..

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

" ptr est un pointeur vers " aller vers la droite ..its ")" maintenant allez à gauche son a "(" sortez, allez bien "()" "à une fonction qui ne prend aucun argument" aller à gauche "et renvoie un pointeur" aller à droite " un tableau "aller à gauche" des entiers "


2
2017-09-19 13:34