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?
c
arrays
pointers
variable-declaration
George
la source
la source
const
etvolatile
, qui sont à la fois importants et délicats, manquent dans cet article.Réponses:
Le troisième est le même que le premier.
La règle générale est la priorité des opérateurs . Cela peut devenir encore plus complexe lorsque des pointeurs de fonction apparaissent dans l'image.
la source
( ) [ ]
s'associent de gauche à droite et ont une priorité plus élevée que*
celle lueint* arr[8]
comme un tableau de taille 8 où chaque élément pointe vers un int etint (*arr)[8]
comme un pointeur vers un tableau de taille 8 qui contient des entiersUtilisez le programme cdecl , comme suggéré par K&R.
Cela fonctionne aussi dans l'autre sens.
la source
Je ne sais pas s'il a un nom officiel, mais je l'appelle Thingy Droite-Gauche (TM).
Commencez par la variable, puis allez à droite, à gauche, à droite ... et ainsi de suite.
arr1
est un tableau de 8 pointeurs vers des entiers.arr2
est un pointeur (la parenthèse bloque la droite-gauche) sur un tableau de 8 entiers.arr3
est un tableau de 8 pointeurs vers des entiers.Cela devrait vous aider avec des déclarations complexes.
la source
int *a[][10]
pendant que le second réussit.( ) [ ]
gauche à droite et de droite à gauche* &
la source
[5]
) représente la dimension intérieure. Cela signifie que(*a[8])
c'est la première dimension, et est donc la représentation externe du tableau. Ce à quoi chaque élément à l'intérieura
pointe est un tableau entier différent de taille 5.La réponse pour les deux derniers peut également être déduite de la règle d'or en C:
int (*arr2)[8];
Que se passe-t-il si vous déréférencez
arr2
? Vous obtenez un tableau de 8 entiers.int *(arr3[8]);
Que se passe-t-il si vous prenez un élément
arr3
? Vous obtenez un pointeur sur un entier.Cela aide également lorsque vous traitez des pointeurs vers des fonctions. Pour prendre l'exemple de sigjuice:
float *(*x)(void )
Que se passe-t-il lorsque vous déréférencez
x
? Vous obtenez une fonction que vous pouvez appeler sans arguments. Que se passe-t-il lorsque vous l'appelez? Il renverra un pointeur sur afloat
.La priorité des opérateurs est cependant toujours délicate. Cependant, l'utilisation de parenthèses peut également être source de confusion car la déclaration suit l'utilisation. Au moins, pour moi, cela
arr2
ressemble intuitivement à un tableau de 8 pointeurs vers des pouces, mais c'est en fait l'inverse. Il suffit de s'y habituer. Raison suffisante pour toujours ajouter un commentaire à ces déclarations, si vous me demandez :)modifier: exemple
Soit dit en passant, je suis juste tombé sur la situation suivante: une fonction qui a une matrice statique et qui utilise l'arithmétique du pointeur pour voir si le pointeur de ligne est hors limites. Exemple:
Production:
Notez que la valeur de border ne change jamais, donc le compilateur peut optimiser cela. Ceci est différent de ce que vous voudrez peut-être utiliser initialement
const int (*border)[3]
:: qui déclare border comme pointeur vers un tableau de 3 entiers qui ne changera pas de valeur tant que la variable existe. Cependant, ce pointeur peut être pointé vers n'importe quel autre tableau de ce type à 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.(ps: n'hésitez pas à améliorer cet échantillon!)
la source
la source
En règle générale, opérateurs unaires à droite (comme
[]
,()
, etc.) donnent leur préférence sur les gauche. Donc, ceint *(*ptr)()[];
serait un pointeur qui pointe vers une fonction qui renvoie un tableau de pointeurs à int (obtenez les bons opérateurs dès que vous le pouvez en sortant de la parenthèse)la source
error: ‘foo’ declared as function returning an array int foo(int arr_2[5][5])[5];
sous GCC 8 avec$ gcc -std=c11 -pedantic-errors test.c
int *(*ptr)();
permet d'utiliser une expression commep()[3]
(ou(*p)()[3]
) plus tard.int *foo(int arr_2[5][5]) { return &(arr_2[2][0]); }
et appelez-le comme ceci:foo(arr)[4];
qui devrait contenirarr[2][4]
, non?Je pense que nous pouvons utiliser la règle simple ..
"
ptr
est un pointeur vers" aller vers la droite .. ses ")" maintenant aller vers la gauche c'est un "(" sortir sortir vers la droite "()" donc "vers une fonction qui ne prend aucun argument" aller vers la gauche "et retourner un pointeur" aller à droite "vers un tableau" aller à gauche "d'entiers"la source
)
, maintenant aller à gauche ... c'est*
"un pointeur pour" aller à droite ... c'est)
, maintenant aller à gauche ... c'est a(
sortir, aller à droite()
donc "vers une fonction qui ne prend aucun argument" aller à droite ...[]
"et retourne un tableau de" aller à droite;
, donc aller à gauche ...*
"pointeurs vers" aller à gauche ...int
"entiers"Voici un site Web intéressant qui explique comment lire des types complexes en C: http://www.unixwiz.net/techtips/reading-cdecl.html
la source
Voici comment je l'interprète:
Donc, ici, nous appliquerons l'
[]
avant*
, ce qui rend la déclaration équivalente à:Cela peut être lu comme, (la valeur de la (valeur au ième index du quelque chose)) est un entier. Ainsi, (valeur au ième index de quelque chose) est un (pointeur entier), ce qui fait de quelque chose un tableau de pointeurs entiers.
Dans le second,
Pour donner un sens à cette déclaration, vous devez être familier avec ce fait:
Donc, en remplaçant
somethingElse
par(*something)
, nous obtenons*(*something + i)
, qui est un entier selon la déclaration. Donc,(*something)
nous a donné un tableau, ce qui fait quelque chose d'équivalent à (pointeur vers un tableau) .la source
Je suppose que la deuxième déclaration prête à confusion pour beaucoup. Voici un moyen simple de le comprendre.
Permet d'avoir un tableau d'entiers, c'est à dire
int B[8]
.Ayons également une variable A qui pointe vers B. Maintenant, la valeur en A est B, c'est-à-dire
(*A) == B
. Par conséquent, A pointe vers un tableau d'entiers. Dans votre question, arr est similaire à A.De même, dans
int* (*C) [8]
, C est un pointeur vers un tableau de pointeurs sur entier.la source
Dans cette déclaration,
arr1
est un tableau de 5 pointeurs vers des entiers. Motif: les crochets ont une priorité plus élevée que * (opérateur de déréfernçage). Et dans ce type, le nombre de lignes est fixe (5 ici), mais le nombre de colonnes est variable.Dans cette déclaration,
arr2
est un pointeur vers un tableau entier de 5 éléments. Raison: ici, les crochets () ont une priorité plus élevée que []. Et dans ce type, le nombre de lignes est variable, mais le nombre de colonnes est fixe (5 ici).la source
Dans le pointeur vers un entier si le pointeur est incrémenté, il passe à l'entier suivant.
dans le tableau du pointeur si le pointeur est incrémenté, il passe au tableau suivant
la source