Erreur de calcul de la taille d’un tableau dans une fonction

Le programme C suivant:

int doStuff(int afm[]); int main(){ int afm1[9] = {1,2,3,4,5,6,7,8,9}; //size=9 int afmLength = sizeof(afm1)/sizeof(int); printf("main: Length Of Array=%d\n", afmLength); //9 OK int k = doStuff(afm1); system("PAUSE"); return 0; } int doStuff(int afm[]){ int afmLength = sizeof(afm)/sizeof(int); printf("doStuff: Length Of Array=%d\n", afmLength); //1 WRONG return 1; } 

produit la sortie suivante:

 main: Length Of Array=9 doStuff: Length Of Array=1 

Pourquoi la taille du tableau est-elle calculée correctement dans main, mais erronée dans la fonction?

Parce que, en main vous avez un tableau et que dans la fonction, vous avez un pointeur sur ce tableau.

 int doStuff(int afm[]) 

est équivalent à

 int doStuff(int *afm) 

En ajoutant à la réponse de David Heffernan (qui est correcte), vous devriez avoir un autre paramètre qui serait la longueur du tableau passé à votre méthode doStuff .

De la norme de langage C (projet n1256 ):

6.3.2.1 Lvalues, tableaux et désignateurs de fonctions

3 Sauf s’il s’agit de l’opérande de l’opérateur sizeof ou de l’opérateur unaire & , ou s’il s’agit d’un littéral utilisé pour initialiser un tableau, une expression de type ” tableau de type ” est convertie en une expression de type ” pointeur taper ” qui pointe vers l’élément initial de l’object tableau et n’est pas une lvalue. Si l’object tableau a une classe de stockage de registre, le comportement n’est pas défini.

Mémorisez ce paragraphe, car l’une des plus grandes sources de brûlures d’estomac dans la programmation en C est la façon dont C traite les expressions de tableau.

Lorsque vous appelez doStuff(afm1); , l’expression afm1 est convertie implicitement du type “tableau à 9 éléments d’ int ” en “pointeur sur int “, et la valeur de l’expression est identique à celle de &afm1[0] . Donc, ce que doStuff reçoit est une valeur de pointeur, pas un tableau.

Dans le contexte d’une déclaration de paramètre de fonction, T a[] et T a[N] sont tous deux interprétés comme T *a :

6.7.5.3 Déclarateurs de fonctions (y compris les prototypes)

7 La déclaration d’un paramètre sous la forme ” tableau de type ” doit être réglée sur ” pointeur qualifié vers type ”, les qualificateurs de type (le cas échéant) étant ceux spécifiés dans les [ et ] de la dérivation de type de tableau. Si le mot clé static apparaît également dans le [ et ] de la dérivation du type de tableau, alors, pour chaque appel à la fonction, la valeur de l’argument réel correspondant doit permettre d’accéder au premier élément d’un tableau avec au moins autant d’éléments que ceux spécifiés. par l’expression de taille.

Étant donné que doStuff reçoit une valeur de pointeur et non un tableau, l’astuce de sizeof ne fonctionne pas. En général, vous devez indiquer explicitement à une fonction la taille d’un tableau que vous lui transmettez; vous ne pouvez pas déterminer cela à partir de la valeur du pointeur lui-même.

Ainsi, lorsque vous appelez doStuff depuis main , vous devez faire quelque chose comme:

 doStuff(afm1, sizeof afm1/sizeof *afm1); ... int doStuff(int *afm, size_t afmsize) { ... }