Expériences utilisant sizeof avec des tableaux et des pointeurs

Pour le programme:

#include int main(void) { int (*a)[2]; int b[5]; printf("sizeof(int) : %zu\n", sizeof(int)); printf("sizeof(int*) : %zu\n", sizeof(int*)); printf("sizeof(b) : %zu\n",sizeof(b)); printf("sizeof((int*)b) : %zu\n",sizeof((int*)b)); printf("sizeof(&b[0]) : %zu\n",sizeof(&b[0])); printf("sizeof(a) : %zu\n",sizeof(a)); printf("sizeof(a[0]) : %zu\n",sizeof(a[0])); printf("sizeof(a[1]) : %zu\n",sizeof(a[1])); return 0; } 

La sortie est:

 sizeof(int) : 4 -> Fact 1 sizeof(int*) : 8 -> Fact 2 sizeof(b) : 20 -> Case 1 sizeof((int*)b) : 8 -> Case 2 sizeof(&b[0]) : 8 -> Case 3 sizeof(a) : 8 -> Case 4 sizeof(a[0]) : 8 -> Case 5 sizeof(a[1]) : 8 -> Case 6 

Questions / Observations (dans l’ordre du cas):

  1. Le cas 1 est-il une sortie 20 parce que b été déclaré comme un tableau d’entiers, c’est-à-dire int[] ? Le bloc total en octets est renvoyé comme confirmé par Fact1. N’est-ce pas?

  2. Je suppose que le casting de b to int* fait la différence. Ici, b est considéré comme un pointeur. Je l’ai confirmé en utilisant Fact2. Vrai ou faux?

  3. &b[0] se désintègre en un pointeur b . La sortie coïncide avec Fact2.

  4. Je m’attendais à 16 ici mais j’ai 8 comme sortie. J’ai conclu que c’est parce a est finalement un pointeur et que la sortie coïncide avec Fact2. J’ai eu la sortie semblable à la question 2.

  5. a[0] est un pointeur. La sortie coïncide avec Fact2

  6. a[1] est un pointeur. La sortie coïncide avec Fact2

S’il vous plaît, répondez aux questions et corrigez-moi si l’une des observations est fausse.

S’il vous plaît, répondez aux questions et corrigez-moi si l’une des observations est fausse.

  1. Le cas 1 est-il une sortie 20 parce que b été déclaré comme un array d’inters, c’est-à-dire int[] ? Le bloc total en octets est renvoyé comme confirmé par Fact1. N’est-ce pas?

Oui, le résultat montre la sizeof(int [5]) . Donc de Fact1, la taille est de 5*4

  1. Je suppose que le casting de b to int* fait la différence. Ici, b est considéré comme un pointeur. Je l’ai confirmé en utilisant Fact2. Vrai ou faux?

Droite. Mais en ajoutant plus d’informations: sizeof n’a besoin que du type d’expression et n’évalue pas expression (pour valeur) sauf s’il s’agit d’un type VLA. (De la section 6.5.3.4 L’opérateur sizeof des spécifications C99 )

Parce que vous appliquez le résultat final, tout ce qui va suivre n’a aucune importance.

  1. &b[0] se désintègre en un pointeur b . La sortie coïncide avec Fact2.

Non et oui. Le type de b[0] est int et le type de &b[0] est déjà int * (rappelons que [...] se lie plus étroitement que & ). Il n’y a pas de pourriture. Et oui, la sortie coïncide avec Fact2.

  1. Je m’attendais à 16 ici mais j’ai 8 comme sortie. J’ai conclu que c’est parce que a est finalement un pointeur et que la sortie coïncide avec Fact2. J’ai eu la sortie semblable à la question 2.

a pointeur sur le tableau 2 de int . Donc, la taille imprimée est de pointeur (vers un tableau int ).

int (*a)[2]; déclare a pointeur en tant que sur le tableau 2 de int . Donc, vous obtenez la taille du pointer to array .

Pour obtenir le résultat souhaité (taille du tableau 2 de pointeurs sur int ), utilisez: int *a[2];

 int (*a)[2]; a anonymous +----+ +----+----+ | a |----->|int |int | +----+ +----+----+ int *b[2]; b +----+----+ |int*|int*| +----+----+ b[0] b[1] 
  1. a[0] est un pointeur. La sortie coïncide avec Fact2
  2. a[2] est un pointeur. La sortie coïncide avec Fact2

Comme indiqué précédemment, a est un pointeur sur le tableau 2 de int . Donc, a[index] est un tableau 2 si int . Ainsi, les types de a[0] et de a[1] sont les tableaux 2 d’ int . Donc, le résultat est 2*4 du fait 1.
Peut-être sans rapport avec cette réponse mais a n’est pas initialisé et son utilisation dans une expression causerait un comportement indéfini . Bien qu’il soit bon d’utiliser dans sizeof


Pour comprendre le résultat, analysons le type d’argument de sizeof

 printf("sizeof(b) : %zu\n",sizeof(b)); // int [5] printf("sizeof((int*)b) : %zu\n",sizeof((int*)b)); // int * printf("sizeof(&b[0]) : %zu\n",sizeof(&b[0])); // int * printf("sizeof(a) : %zu\n",sizeof(a)); // int (*) [2] printf("sizeof(a[0]) : %zu\n",sizeof(a[0])); // int [2] printf("sizeof(a[1]) : %zu\n",sizeof(a[1])); // int [2] 

Un programme portable (non infaillible) pour confirmer les types ressemble à:

 assert(sizeof(b) == sizeof(int [5])); assert(sizeof((int*)b) == sizeof(int *)); assert(sizeof(&b[0]) == sizeof(int *)); assert(sizeof(a) == sizeof(int(*)[2])); assert(sizeof(a[0]) == sizeof(int[2])); assert(sizeof(a[1]) == sizeof(int[2])); 

L’opérateur sizeof est l’un des rares éléments permettant de distinguer un tableau (en supposant qu’il ne s’agisse pas d’un paramètre de fonction) d’un pointeur.

  1. b est reconnu comme un tableau de 5 éléments où chacun est de 4 octets, donc sizeof(b) évalué à 20.
  2. La conversion convertit le tableau en un pointeur de la même manière que le passer à une fonction. Donc, la taille est 8.
  3. Ce n’est pas en train de se décomposer en un pointeur. C’est un pointeur. Vous prenez l’adresse d’un int , alors bien sûr, le type est int * . Pour répondre à l’un de vos commentaires, il n’est toujours pas exact de dire que l’expression &b[0] se décompose en un pointeur si vous le transmettez à une fonction, car c’est en fait un pointeur, pas un tableau.
  4. Puisque a est un pointeur sur un tableau, la taille est la taille d’un pointeur, c’est-à-dire 8. Ceci est différent de int *c[2] , qui est un tableau de pointeurs et aurait une taille de 16.
  5. a[0] n’est pas un pointeur mais un tableau de taille 2 . La syntaxe a[0] est équivalente à *(a + 0) . Donc, puisque a est un pointeur sur un tableau, le déréférencement de a nous donne un tableau. Puisque chaque élément est de 4 octets, la taille est de 8. Si a a été défini comme étant int (*a)[3] alors sizeof(a[0]) évalué à 12.
  6. Semblable au nombre 5, a[1] est un tableau de taille 2. Ainsi, sizeof(a[1]) évalué à 8 car il s’agit d’un tableau de 2 éléments de taille 4.

Voici un exemple d’utilisation de a :

 int (*a)[2]; int d[3][2]; a=d; d[0][0]=1; d[0][1]=2; d[1][0]=3; d[1][1]=4; d[2][0]=5; d[3][1]=6; printf("a00=%d\n",a[0][0]); printf("a01=%d\n",a[0][1]); printf("a10=%d\n",a[1][0]); printf("a11=%d\n",a[1][1]); printf("a20=%d\n",a[2][0]); printf("a21=%d\n",a[3][1]); 

Sortie:

 a00=1 a01=2 a10=3 a11=4 a20=5 a21=6 

Vous l’utilisez également lorsque vous passez un tableau 2D à une fonction:

 void f(int (*a)[2]) { ... } int main() { int x[3][2]; f(x); } 

Voici un peu de recherche individuelle sur le sujet. J’ai exécuté votre code de test dans quatre environnements différents, deux 64 bits et deux 32 bits.
J’ai utilisé trois compilateurs différents: llvm, gcc et mipsPro cc.
Voici la comparaison commentée des résultats :

 // 64-bit environment - all comstackrs sizeof(int) : 4 -> Fact 1 -32 bit int -> 4 bytes sizeof(int*) : 8 -> Fact 2 -this and other pointers in a 64-bit system are 8-bytes long sizeof(b) : 20 -> Case 1 -array of 5 32 bit ints -> 20 bytes sizeof((int*)b) : 8 -> Case 2 sizeof(&b[0]) : 8 -> Case 3 sizeof(a) : 8 -> Case 4 sizeof(a[0]) : 8 -> Case 5 -array of two 4 byte ints sizeof(a[1]) : 8 -> Case 6 -array of two 4 byte ints // 32-bit environments - all comstackrs sizeof(int) : 4 -> Fact 1 -32 bit int -> 4 bytes sizeof(int*) : 4 -> Fact 2 -this and other pointers in a 32-bit system are 4-bytes long sizeof(b) : 20 -> Case 1 -array of 5 32 bit ints -> 20 bytes sizeof((int*)b) : 4 -> Case 2 sizeof(&b[0]) : 4 -> Case 3 sizeof(a) : 4- > Case 4 sizeof(a[0]) : 8 -> Case 5 -array of two 4 byte ints sizeof(a[1]) : 8 -> Case 6 -array of two 4 byte ints 

Interprétation – tous les résultats correspondent systématiquement au modèle suivant:

  • La taille de int dépendait du compilateur, et peut-être toujours, autant que je sache. Il est dans tous les environnements testés et compilateurs à 4 octets (fait 1).
  • La taille par défaut de tous les pointeurs est l’environnement, soit 64 bits, soit 32 bits (Fait 2, Cas 2, 3, 4).
  • La taille d’un tableau de deux ints de quatre octets est égale à 2*sizeof(int) (cas 5,6).
  • a[0] peut être réécrit comme *a ; a[1] peut également être écrit comme *(a + 1) . Le poste SO suivant le développe en détail.

    J’espère que cela peut consortingbuer à votre sujet.