web-dev-qa-db-fra.com

Pourquoi la taille d'un paramètre de tableau n'est-elle pas identique à celle de main?

Pourquoi la taille d'un tableau envoyé en tant que paramètre n'est-elle pas identique à celle de main?

#include <stdio.h>

void PrintSize(int p_someArray[10]);

int main () {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* As expected, 40 */
    PrintSize(myArray);/* Prints 4, not 40 */
}

void PrintSize(int p_someArray[10]){
    printf("%d\n", sizeof(p_someArray));
}
99
Chris_45

Un type de tableau est implicitement converti en type pointeur lorsque vous le transmettez à une fonction.

Alors,

void PrintSize(int p_someArray[10]) {
    printf("%zu\n", sizeof(p_someArray));
}

et

void PrintSize(int *p_someArray) {
    printf("%zu\n", sizeof(p_someArray));
}

sont équivalents. Donc, ce que vous obtenez est la valeur de sizeof(int*)

99
Prasoon Saurav

C'est un pointeur, c'est pourquoi c'est une implémentation courante de passer la taille du tableau en tant que second paramètre à la fonction

18
user240312

Comme d'autres l'ont indiqué, les tableaux se désintègrent en pointeurs vers leur premier élément lorsqu'ils sont utilisés comme paramètres de fonction. Il est également intéressant de noter que sizeof n'évalue pas l'expression et ne nécessite pas de parenthèses lorsqu'il est utilisé avec une expression. Votre paramètre n'est donc pas utilisé du tout. Vous pouvez donc également écrire le sizeof avec le type plutôt que la valeur.

#include <stdio.h>

void PrintSize1 ( int someArray[][10] );
void PrintSize2 ( int someArray[10] );

int main ()
{
    int myArray[10];
    printf ( "%d\n", sizeof myArray ); /* as expected 40 */
    printf ( "%d\n", sizeof ( int[10] ) ); /* requires parens */
    PrintSize1 ( 0 ); /* prints 40, does not evaluate 0[0] */
    PrintSize2 ( 0 ); /* prints 40, someArray unused */
}

void PrintSize1 ( int someArray[][10] )
{
    printf ( "%d\n", sizeof someArray[0] );
}

void PrintSize2 ( int someArray[10] )
{
    printf ( "%d\n", sizeof ( int[10] ) );
}
16
Pete Kirkham

Donc, vous devrez passer la longueur du tableau en tant que second paramètre. Lorsque vous écrivez du code, dans lequel vous déclarez tous les deux un tableau de taille constante, puis que vous transmettez ce tableau à une fonction, il est très pénible de voir la constante de longueur de tableau afficher plusieurs emplacements dans votre code ...

K & R à la rescousse:

#define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0])) 

Alors maintenant, vous pouvez faire par exemple:

int a[10];
...
myfunction(a, N_ELEMENTS(a));
12
S.C. Madsen

Le comportement que vous avez trouvé est en fait une grosse verrue en langage C. Chaque fois que vous déclarez une fonction qui prend un paramètre de tableau, le compilateur vous ignore et modifie le paramètre en pointeur. Donc, ces déclarations se comportent toutes comme la première:

void func(int *a)
void func(int a[])
void func(int a
typedef int array_plz[5];
void func(array_plz a)

a sera un pointeur sur int dans les quatre cas. Si vous passez un tableau à func, il se décomposera immédiatement en un pointeur sur son premier élément. (Sur un système 64 bits, un pointeur 64 bits est deux fois plus grand qu'un int 32 bits, votre ratio sizeof renvoie donc 2.)

Le seul but de cette règle est de maintenir une compatibilité ascendante avec les compilateurs historiques qui ne prennent pas en charge le passage de valeurs d'agrégat en tant qu'arguments de fonction.

Cela ne signifie pas qu’il est impossible de passer un tableau à une fonction. Vous pouvez contourner ce problème en incorporant le tableau dans une structure (c’est le but de std :: array de C++ 11):

struct array_rly {
int a[5];
};
void func(struct array_rly a)
{
printf("%zd\n", sizeof(a.a)/sizeof(a.a[0]));  /* prints 5 */
}

ou en passant un pointeur sur le tableau:

void func(const int (*a)[5])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints 5 */
}

Si la taille du tableau n’est pas une constante de compilation, vous pouvez utiliser la technique du pointeur vers le tableau avec les tableaux de longueur variable C99:

void func(int n, const int (*a)[n])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints n */
}
5
Walter

Parce que les tableaux se décomposent en pointeurs lorsqu'ils sont passés en tant que paramètres. Voici comment fonctionne C, bien que vous puissiez passer "des tableaux" en C++ par référence et résoudre ce problème. Notez que vous pouvez transmettre des tableaux de différentes tailles à cette fonction:

 // 10 is superfluous here! You can pass an array of different size!
void PrintSize(int p_someArray[10]);
5
AraK

En c ++, vous pouvez passer un tableau par référence dans ce but précis:

void foo(int (&array)[10])
{
    std::cout << sizeof(array) << "\n";
}
4
Alexandre C.

Dans le langage C, il n’existe aucune méthode permettant de déterminer la taille d’un tableau inconnu. La quantité doit donc être transmise ainsi qu’un pointeur sur le premier élément.

3
user195488

Vous ne pouvez pas passer de tableaux à des fonctions.

Si vous voulez vraiment imprimer la taille, vous pouvez passer un pointeur sur un tableau, mais celui-ci ne sera pas générique, car vous devez également définir la taille du tableau pour la fonction.

#include <stdio.h>

void PrintSize(int (*p_anArray)[10]);

int main(void) {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* as expected 40 */
    PrintSize(&myArray);/* prints 40 */
}

void PrintSize(int (*p_anArray)[10]){
    printf("%d\n", (int) sizeof(*p_anArray));
}
3
MR.

Le comportement est par conception.

Même syntaxe dans la déclaration de paramètre de fonction signifie une chose complètement différente de celle dans la définition de variable locale.

La raison est décrite dans d'autres réponses.

0
Pavel Radzivilovsky

En langage C, lorsque vous passez le tableau en tant qu'argument à la fonction, il est automatiquement converti en pointeur, le tableau passant d'une fonction à une autre fonction étant appelé appel par référence. C’est la raison pour laquelle la fonction appelée ne reçoit que le pointeur qui pointe vers le premier élément de la fonction. C’est la raison

fun (int a []) est similaire à fun (int * a);

ainsi, lorsque vous imprimez la taille d'un tableau, il affichera la taille du premier élément.

0
dagrawal