web-dev-qa-db-fra.com

Comment trouver le 'sizeof' (un pointeur pointant sur un tableau)?

Tout d'abord, voici un code:

int main() 
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

Existe-t-il un moyen de connaître la taille du tableau indiqué par ptr (au lieu de simplement donner sa taille, qui est de quatre octets sur un système 32 bits)?

282
jkidv

Non, tu ne peux pas. Le compilateur ne sait pas sur quoi le pointeur pointe. Il y a des astuces, comme terminer le tableau avec une valeur hors bande connue, puis compter la taille jusqu'à cette valeur, mais ce n'est pas en utilisant sizeof.

Une autre astuce est celle mentionnée par Zan , qui consiste à cacher la taille quelque part. Par exemple, si vous allouez dynamiquement le tableau, allouez un bloc supérieur à celui dont vous avez besoin, stockez la taille dans le premier int et renvoyez ptr + 1 en tant que pointeur sur le tableau. Lorsque vous avez besoin de la taille, décrémentez le pointeur et examinez la valeur stockée. Rappelez-vous simplement de libérer le bloc entier à partir du début, et pas seulement le tableau.

245
Paul Tomblin

La réponse est non."

Les programmeurs C stockent la taille du tableau quelque part. Cela peut faire partie d'une structure, ou le programmeur peut tricher un peu et malloc () plus de mémoire que demandé pour stocker une valeur de longueur avant le début du tableau.

76
Zan Lynx

Pour les tableaux dynamiques ( malloc ou C++ new ), vous devez stocker le taille du tableau telle que mentionnée par d'autres ou peut-être créer une structure de gestionnaire de tableau qui gère ajouter, supprimer, compter, etc. Malheureusement, C ne le fait pas aussi bien que C++ car vous devez le construire pour chaque type de tableau stockent ce qui est fastidieux si vous devez gérer plusieurs types de tableaux.

Pour les tableaux statiques, tels que celui de votre exemple, il existe une macro commune utilisée pour obtenir la taille, mais elle est non recommandé car elle ne vérifie pas si le paramètre est vraiment un tableau statique. La macro est utilisée dans du code réel, p. Ex. dans les en-têtes du noyau Linux bien que cela puisse être légèrement différent de celui ci-dessous:

#if !defined(ARRAY_SIZE)
    #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
#endif

int main()
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", ARRAY_SIZE(days));
    printf("%u\n", sizeof(ptr));
    return 0;
}

Vous pouvez google pour des raisons de se méfier des macros comme celle-ci. Faites attention.

Si possible, la bibliothèque stdlib C++, telle que le vecteur, est beaucoup plus sûre et facile à utiliser.

45
Ryan

Il existe une solution propre avec des modèles C++, sans utiliser sizeof (). La fonction getSize () suivante renvoie la taille de tout tableau statique:

#include <cstddef>

template<typename T, size_t SIZE>
size_t getSize(T (&)[SIZE]) {
    return SIZE;
}

Voici un exemple avec une structure foo_t:

#include <cstddef>

template<typename T, size_t SIZE>
size_t getSize(T (&)[SIZE]) {
    return SIZE;
}

struct foo_t {
    int ball;
};

int main()
{
    foo_t foos3[] = {{1},{2},{3}};
    foo_t foos5[] = {{1},{2},{3},{4},{5}};
    printf("%u\n", getSize(foos3));
    printf("%u\n", getSize(foos5));

    return 0;
}

Sortie:

3
5
17
skurton

Pour cet exemple spécifique, oui, SI, vous utilisez des typedefs (voir ci-dessous). Bien sûr, si vous le faites de cette façon, vous feriez bien d’utiliser SIZEOF_DAYS, puisque vous savez à quoi le pointeur se réfère.

Si vous avez un pointeur (void *), tel que renvoyé par malloc () ou similaire, alors, non, il n'y a aucun moyen de déterminer la structure de données pointée par le pointeur ni, par conséquent, de déterminer sa taille.

#include <stdio.h>

#define NUM_DAYS 5
typedef int days_t[ NUM_DAYS ];
#define SIZEOF_DAYS ( sizeof( days_t ) )

int main() {
    days_t  days;
    days_t *ptr = &days; 

    printf( "SIZEOF_DAYS:  %u\n", SIZEOF_DAYS  );
    printf( "sizeof(days): %u\n", sizeof(days) );
    printf( "sizeof(*ptr): %u\n", sizeof(*ptr) );
    printf( "sizeof(ptr):  %u\n", sizeof(ptr)  );

    return 0;
} 

Sortie:

SIZEOF_DAYS:  20
sizeof(days): 20
sizeof(*ptr): 20
sizeof(ptr):  4
5
David

Il n'y a pas de solution magique. C n'est pas un langage de réflexion. Les objets ne savent pas automatiquement ce qu'ils sont.

Mais vous avez beaucoup de choix:

  1. Évidemment, ajoutez un paramètre
  2. Emballer l'appel dans une macro et ajouter automatiquement un paramètre
  3. Utilisez un objet plus complexe. Définissez une structure qui contient le tableau dynamique ainsi que la taille du tableau. Ensuite, passez l'adresse de la structure.
4
DigitalRoss

Comme toutes les réponses correctes l'ont indiqué, vous ne pouvez pas obtenir cette information à partir de la valeur du pointeur décomposé du tableau uniquement. Si le pointeur caduque est l'argument reçu par la fonction, la taille du tableau d'origine doit être fournie d'une autre manière pour que la fonction puisse connaître cette taille.

Voici une suggestion différente de ce qui a été fourni jusqu'à présent, qui fonctionnera: passez un pointeur sur le tableau. Cette suggestion est similaire aux suggestions de style C++, sauf que C ne prend pas en charge les modèles ou les références:

#define ARRAY_SZ 10

void foo (int (*arr)[ARRAY_SZ]) {
    printf("%u\n", (unsigned)sizeof(*arr)/sizeof(**arr));
}

Mais, cette suggestion est un peu ridicule pour votre problème, car la fonction est définie pour connaître exactement la taille du tableau qui est passé (par conséquent, il n’est guère nécessaire d’utiliser sizeof sur le tableau). Ce qu'il fait, cependant, c'est offrir une certaine sécurité. Cela vous empêchera de transmettre un tableau de taille indésirable.

int x[20];
int y[10];
foo(&x); /* error */
foo(&y); /* ok */

Si la fonction est supposée pouvoir fonctionner avec n'importe quelle taille de tableau, vous devrez alors fournir la taille à la fonction en tant qu'informations supplémentaires.

3
jxh
int main() 
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

Size of days [] est égal à 20, ce qui correspond au nombre d'éléments * taille de son type de données. Alors que la taille du pointeur est 4, peu importe ce qu'il pointe. Parce qu'un pointeur pointe sur un autre élément en stockant son adresse.

2
Shivangi Chaurasia

Ma solution à ce problème consiste à enregistrer la longueur du tableau dans un struct Array en tant que méta-information sur le tableau.

#include <stdio.h>
#include <stdlib.h>

struct Array
{
    int length;

    double *array;
};

typedef struct Array Array;

Array* NewArray(int length)
{
    /* Allocate the memory for the struct Array */
    Array *newArray = (Array*) malloc(sizeof(Array));

    /* Insert only non-negative length's*/
    newArray->length = (length > 0) ? length : 0;

    newArray->array = (double*) malloc(length*sizeof(double));

    return newArray;
}

void SetArray(Array *structure,int length,double* array)
{
    structure->length = length;
    structure->array = array;
}

void PrintArray(Array *structure)
{       
    if(structure->length > 0)
    {
        int i;
        printf("length: %d\n", structure->length);
        for (i = 0; i < structure->length; i++)
            printf("%g\n", structure->array[i]);
    }
    else
        printf("Empty Array. Length 0\n");
}

int main()
{
    int i;
    Array *negativeTest, *days = NewArray(5);

    double moreDays[] = {1,2,3,4,5,6,7,8,9,10};

    for (i = 0; i < days->length; i++)
        days->array[i] = i+1;

    PrintArray(days);

    SetArray(days,10,moreDays);

    PrintArray(days);

    negativeTest = NewArray(-5);

    PrintArray(negativeTest);

    return 0;
}

Mais vous devez vous préoccuper de définir la bonne longueur du tableau que vous voulez stocker, car il n’ya aucun moyen de vérifier cette longueur, comme l’a expliqué massivement nos amis.

2
user4713908

Vous pouvez faire quelque chose comme ça:

int days[] = { /*length:*/5, /*values:*/ 1,2,3,4,5 };
int *ptr = days + 1;
printf("array length: %u\n", ptr[-1]);
return 0;

Non, vous ne pouvez pas utiliser sizeof(ptr) pour trouver la taille du tableau pointé par ptr.

Bien qu’allouer de la mémoire supplémentaire (plus que la taille d’un tableau) sera utile si vous souhaitez stocker la longueur dans un espace supplémentaire.

1
SKD
 #define array_size 10

 struct {
     int16 size;
     int16 array[array_size];
     int16 property1[(array_size/16)+1]
     int16 property2[(array_size/16)+1]
 } array1 = {array_size, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

 #undef array_size

array_size passe à la taille variable:

#define array_size 30

struct {
    int16 size;
    int16 array[array_size];
    int16 property1[(array_size/16)+1]
    int16 property2[(array_size/16)+1]
} array2 = {array_size};

#undef array_size

L'utilisation est:

void main() {

    int16 size = array1.size;
    for (int i=0; i!=size; i++) {

        array1.array[i] *= 2;
    }
}
0
user3065147