int q[10]={0};
cout << q << endl;
cout << &q << endl;
cout << &q[0] << endl;

La sortie est

0x7fffd4d2f860 
0x7fffd4d2f860 
0x7fffd4d2f860 

Maintenant, quand je fais ça->

int *r=q;    // allowed
int *r=&q[0] // allowed
int *r=&q    // not allowed

Pourquoi la troisième affectation n'est-elle pas autorisée alors que c'est essentiellement la même chose?

4
james gem 21 mars 2020 à 01:12

3 réponses

Meilleure réponse

Si vous avez un tableau déclaré comme

T a[N];

T est un spécificateur de type, un pointeur vers le tableau sera déclaré comme

T ( *p )[N] = &a;

Une règle générale est la suivante. Si vous avez un tableau multidimensionnel (y compris des tableaux unidimensionnels) comme par exemple

T a[N1][N2][N3];

Alors cette déclaration, vous pouvez la réécrire comme

T ( a[N1] )[N2][N3];

Pour obtenir un pointeur sur le premier élément du tableau, remplacez simplement le contenu entre parenthèses de la manière suivante

T ( *p )[N2][N3] = a;

Si vous voulez obtenir un pointeur sur tout le tableau, réécrivez la déclaration du tableau comme

T ( a )[N1][N2][N3];

Et faire la substitution

T ( *p )[N1][N2][N3] = &a;

Comparez cela avec une déclaration d'un objet scalaire et un pointeur sur celui-ci.

Par exemple

T obj;

Vous pouvez réécrire la déclaration comme

T ( obj );

Maintenant, pour obtenir un pointeur sur l'objet, vous pouvez écrire

T ( *p ) = &obj;

Bien sûr, dans ce cas, les parenthèses sont redondantes et la déclaration ci-dessus équivaut à

T *p = &obj;

Quant à cet extrait de code

int q[10]={0};
cout << q << endl;
cout << &q << endl;
cout << &q[0] << endl;

Et sa sortie

0x7fffd4d2f860 
0x7fffd4d2f860 
0x7fffd4d2f860 

Puis les désignateurs de tableau utilisés dans les expressions avec de rares exceptions sont convertis en pointeurs vers leurs premiers éléments.

Donc, en fait, les deux expressions q et &q[0] dans ces instructions

cout << q << endl;
cout << &q[0] << endl;

Sont équivalents. D'un autre côté, l'adresse du tableau lui-même est l'adresse de l'étendue de mémoire que le tableau occupe. Et au début de l'étendue, il y a le premier élément du tableau. Les trois expressions donnent donc le même résultat: l'adresse de l'étendue de mémoire occupée par le tableau.

10
Vlad from Moscow 20 mars 2020 à 22:36

Vous ne pouvez pas effectuer la troisième affectation car le type de &q est un int (*)[10], ce qui est incompatible avec le type de int* r.

La sortie de cout << &q ne révèle pas le type de &q. Voir ce lien de documentation.

2
Kurt Stolle 20 mars 2020 à 22:26

Pourquoi la troisième affectation n'est-elle pas autorisée alors que c'est essentiellement la même chose?

Parce que le langage C ++ a une fonctionnalité appelée "sécurité de type". Il existe un système de type qui vous aide à garder la logique du son de votre programme.

Une règle particulière est que les types de pointeurs arbitraires ne peuvent pas être utilisés pour initialiser des pointeurs d'autres types incompatibles. Dans ce cas, vous avez un pointeur pour taper int (.i.e. int*) que vous essayez d'initaliser avec une expression de type pointer pour taper un tableau de 10 int (c'est-à-dire int(*)[10]). Un type n'est pas implicitement convertible en l'autre, donc le programme est mal formé.

Alors pourquoi cout imprime-t-il les mêmes choses dans les trois cas?

Parce que tous les pointeurs ont la même valeur. Le premier octet du premier élément du tableau est le même octet que le premier octet de l'ensemble du tableau.

1

1


Pourquoi ne pouvons-nous pas attribuer l'adresse du tableau au pointeur?

En fait, nous pouvons attribuer l'adresse d'un tableau à un pointeur. Nous ne pouvons tout simplement pas attribuer l'adresse d'un tableau (ou tout autre objet d'ailleurs) à un pointeur de mauvais type . Nous avons besoin d'un pointeur vers un tableau dans ce cas:

int (*r)[10] = &q;
4
eerorika 20 mars 2020 à 22:31