Comment un pointeur de tableau stocke-t-il sa taille?

#include "stdio.h" #define COUNT(a) (sizeof(a) / sizeof(*(a))) void test(int b[]) { printf("2, count:%d\n", COUNT(b)); } int main(void) { int a[] = { 1,2,3 }; printf("1, count:%d\n", COUNT(a)); test(a); return 0; } 

Le résultat est évident:

 1, count:3 2, count:1 

Mes questions:

  1. Où les informations de longueur (nombre / taille) sont-elles stockées lorsque “a” est déclaré?
  2. Pourquoi les informations de longueur (nombre / taille) sont-elles perdues lorsque “a” est transmis à la fonction test ()?

Il n’existe pas de “pointeur de masortingce” en langage C.

La taille n’est pas stockée nulle part. a n’est pas un pointeur, a est un object de type int[3] , ce qui est bien connu du compilateur au moment de la compilation. Ainsi, lorsque vous demandez au compilateur de calculer sizeof(a) / sizeof(*a) au moment de la compilation, le compilateur sait que la réponse est 3 .

Lorsque vous passez votre a à la fonction, vous demandez intentionnellement au compilateur de convertir le type de tableau en type de pointeur (puisque vous avez déclaré le paramètre de fonction sous forme de pointeur). Pour les pointeurs, votre expression sizeof produit un résultat complètement différent.

  1. Où les informations de longueur (nombre / taille) sont-elles stockées lorsque “a” est déclaré?

Ce n’est pas stocké nulle part. L’opérateur sizeof (utilisé dans la macro COUNT() ) renvoie la taille de l’ensemble du tableau lorsqu’il reçoit un tableau vrai comme opérande (comme dans le premier printf() )

  1. Pourquoi les informations de longueur (nombre / taille) sont-elles perdues lorsque “a” est transmis à la fonction test ()?

Malheureusement, en C, les parameters de tableau en fonctions sont une fiction. Les tableaux ne sont pas transmis aux fonctions; le paramètre est traité comme un pointeur et l’argument de tableau passé dans l’appel de fonction devient “décomposé” en un simple pointeur. L’opérateur sizeof renvoie la taille du pointeur, qui n’a aucune corrélation avec la taille du tableau utilisé comme argument.

En note ++, en C ++, un paramètre de fonction peut être une référence à un tableau. Dans ce cas, le type de tableau complet est mis à la disposition de la fonction (l’argument ne se décompose pas en un pointeur et sizeof retournera la taille du tableau complet). Cependant, dans ce cas, l’argument doit correspondre exactement au type de tableau (y compris le nombre d’éléments), ce qui rend la technique principalement utile uniquement avec des modèles.

Par exemple, le programme C ++ suivant fera ce que vous attendez:

 #include "stdio.h" #define COUNT(a) (sizeof(a) / sizeof(*(a))) template  void test(int (&b)[T]) { printf("2, count:%d\n", COUNT(b)); } int main(int argc, char *argv[]) { int a[] = { 1,2,3 }; printf("1, count:%d\n", COUNT(a)); test(a); return 0; } 
  1. Nulle part.
  2. Parce qu’il n’a pas été stocké en premier lieu.

Lorsque vous faites référence au tableau dans main() , la définition de déclaration de tableau réelle est visible. Ainsi, sizeof(a) donne la taille du tableau en octets.

Lorsque vous vous référez au tableau de la fonction, le paramètre est effectivement ‘ void test(int *b) , et la taille du pointeur divisée par la taille de l’élément pointé se trouve être 1 sur une plate-forme 32 bits, alors que ce serait 2 sur une plate-forme 64 bits avec une architecture LP64 (ou, en fait, sur une plate-forme LLP64 telle que Windows-64) car les pointeurs sont de 8 octets et int 4 octets.

Il n’y a pas de moyen universel pour déterminer la taille d’un tableau passé à une fonction. vous devez le transmettre explicitement et manuellement.


Du commentaire:

J’ai encore deux questions:

  1. Que voulez-vous dire par “..la déclaration réelle est visible ..”? Le compilateur (ou le système d’exploitation) pourrait-il obtenir les informations de longueur via la fonction sizeof (a)?
  2. Pourquoi le pointeur & (a [0]) ne contient-il pas les informations de longueur sous la forme du pointeur “a”?
  1. Je pense que vous avez appris Java avant le C, ou un autre langage plus moderne. En fin de compte, cela revient à “parce que c’est ainsi que C est défini”. Le système d’exploitation n’est pas impliqué; c’est un problème purement compilateur.

    • sizeof() est un opérateur, pas une fonction. Sauf si vous avez affaire à un VLA (tableau de longueur variable), il est évalué au moment de la compilation et est une valeur constante.

    Dans main() , la définition du tableau (je me suis mal exprimé lorsque j’ai dit «déclaration») est présente, et lorsque l’opérateur sizeof() est appliqué au nom d’un tableau réel – par opposition à un paramètre de tableau d’une fonction -, taille renvoyée est la taille du tableau en octets.

  2. Parce que c’est C et non Algol, Pascal, Java, C #, …

    C ne stocke pas la taille du tableau – période. C’est un fait de la vie. Et, lorsqu’un tableau est transmis à une fonction, les informations de taille ne sont pas transmises à la fonction. le tableau ‘se décompose’ en un pointeur sur l’élément zeroth du tableau – et seul ce pointeur est transmis.

 1. Where is the length(count/size) info stored when "a" is declared? 

Ce n’est pas stocké. Le compilateur sait ce qu’est un et donc sa taille. Le compilateur peut donc remplacer sizeof() par la taille réelle.

 2. Why is the length(count/size) info lost when "a" is passed to the test() function? 

Dans ce cas, b est déclaré en tant que pointeur (même s’il peut pointer sur a). Étant donné un pointeur, le compilateur ne connaît pas la taille des données pointées.

  1. Où les informations de longueur (nombre / taille) sont-elles stockées lorsque “a” est déclaré?

Nulle part. La question n’a pas de sens BTW.

  1. Pourquoi les informations de longueur (nombre / taille) sont-elles perdues lorsque “a” est transmis à la fonction test ()?

Le tableau se désintègre en pointeur (vers le premier élément) lorsqu’il est transmis à une fonction. La réponse est donc “nulle part” et, comme dans la question précédente, celle-ci n’a plus aucun sens.

Le pointeur de tableau ne stocke pas la taille. Cependant, le type [] n’est pas réellement un pointeur. C’est un type différent. Quand vous dites int a[] = {1,2,3}; vous définissez un tableau de 3 éléments, et comme il est défini ainsi, sizeof (a) vous donne la taille de tout le tableau.

Cependant, lorsque vous déclarez paramètre en tant que int [], c’est à peu près la même chose que int * a, et sizeof (a) correspond à la taille du pointeur (qui peut être identique à celle de int , mais pas toujours) .

En C, il n’existe aucun moyen de stocker la taille dans un type de pointeur. Par conséquent, si vous avez besoin de la taille, vous devez la passer comme argument supplémentaire ou utiliser struct .