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("%un", sizeof(days));
    printf("%un", sizeof(ptr));

    return 0;
}

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

252
demandé sur Jonathan Leffler 2009-01-29 19:33:34

14 réponses

Non, vous ne pouvez pas. le compilateur ne sait pas sur quoi pointe le pointeur. Il y a des astuces, comme mettre fin au tableau avec une valeur hors bande connue, puis compter la taille jusqu'à cette valeur, mais cela n'utilise pas sizeof.

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

220
répondu Paul Tomblin 2017-05-23 12:34:59

La réponse est "Non."

Ce que font les programmeurs C est de stocker la taille du tableau quelque part. Il peut faire partie d'une structure, ou le programmeur peut tricher un peu et malloc() plus de mémoire que demandé afin de stocker une valeur de longueur Avant le début du tableau.

70
répondu Zan Lynx 2012-02-01 20:27:36

Pour les tableaux dynamiques (malloc ou C++ new), vous devez stocker la taille du tableau comme mentionné par d'autres ou peut-être construire une structure de gestionnaire de tableau qui gère add, remove, count, etc. Malheureusement, C ne le fait pas aussi bien que c++ puisque vous devez essentiellement le construire pour chaque type de tableau différent que vous stockez, ce qui est lourd si vous avez plusieurs types de tableaux que vous devez gérer.

Pour les tableaux statiques, comme celui de votre exemple, il y a une macro commune utilisée pour obtenir la taille, mais elle est déconseillée car elle ne vérifie pas si le paramètre est vraiment un tableau statique. La macro est cependant utilisée dans le code réel, par exemple dans les en-têtes du noyau Linux bien qu'elle puisse être légèrement différente de celle 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 raisons de se méfier des macros comme cela. Être prudent.

Si possible, le C++ stdlib tel que vector qui est beaucoup plus sûr et plus facile à utiliser.

40
répondu Ryan 2015-07-14 22:53:31

Il existe une solution propre avec des modèles C++, sans utiliser sizeof () . La fonction getSize() suivante renvoie la taille d'un 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
18
répondu skurton 2012-04-20 12:18:11

Pour cet exemple spécifique, oui, il y en a, Si vous utilisez typedefs (voir ci-dessous). Bien sûr, si vous le faites de cette façon, vous êtes tout aussi bien à utiliser SIZEOF_DAYS, puisque vous savez ce que le pointeur pointe.

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 vers laquelle le pointeur pointe et donc, aucun moyen 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
répondu David 2011-04-13 21:04:15

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

, Mais vous avez beaucoup de choix:

  1. évidemment, ajoutez un paramètre
  2. enveloppe l'appel dans une macro et ajoute automatiquement un paramètre
  3. utilise un objet plus complexe. Définir une structure qui contient le tableau dynamique et aussi la taille du tableau. Ensuite, passez l'adresse de la structure.
4
répondu DigitalRoss 2016-07-25 20:50:19

Comme toutes les bonnes réponses l'ont indiqué, vous ne pouvez pas obtenir cette information à partir de la valeur de pointeur cariée du tableau seul. Si le pointeur carié est l'argument reçu par la fonction, alors la taille du tableau d'origine doit être fournie d'une autre manière pour que la fonction connaisse cette taille.

Voici une suggestion différente de ce qui a été fourni jusqu'à présent, qui fonctionnera: Passez un pointeur sur le tableau à la place. Cette suggestion est similaire au style C++ suggestions, 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 stupide pour votre problème, puisque la fonction est définie pour connaître exactement la taille du tableau qui est passé (par conséquent, il n'est pas nécessaire d'utiliser sizeof du tout sur le tableau). Ce qu'il fait, cependant, est d'offrir une certaine sécurité de type. Il vous interdira de passer dans un tableau d'une taille indésirable.

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

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

3
répondu jxh 2013-04-09 17:21:56

Ma solution à ce problème est d'enregistrer la longueur du tableau dans un tableau struct en tant que méta-informations 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 soucier de définir la bonne longueur du tableau que vous voulez stocker, car il n'y a aucun moyen de vérifier cette longueur, comme nos amis l'ont massivement expliqué.

2
répondu 2015-10-05 14:45:29
int main() 
{
    int days[] = {1,2,3,4,5};
    int *ptr = days;
    printf("%u\n", sizeof(days));
    printf("%u\n", sizeof(ptr));

    return 0;
}

La taille des jours [] est 20, ce qui n'est pas d'éléments * taille de son type de données. Alors que la taille du pointeur est de 4, peu importe ce qu'il désigne. Parce qu'un pointeur pointe vers un autre élément en stockant son adresse.

2
répondu Shivangi Chaurasia 2016-07-10 10:32:16

Non, vous ne pouvez pas utiliser sizeof(ptr) pour trouver la taille du tableau vers lequel pointe ptr.

Bien que l'allocation de mémoire supplémentaire (plus que la taille du tableau) sera utile si vous voulez stocker la longueur dans un espace supplémentaire.

1
répondu SKD 2016-03-15 11:22:40
 #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 est de passer à 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
répondu user3065147 2015-07-14 22:58:40

Vous pouvez faire quelque chose comme ceci:

int days[] = { /*length:*/5, /*values:*/ 1,2,3,4,5 };
int *ptr = days + 1;
printf("array length: %u\n", ptr[-1]);
return 0;
0
répondu Tᴏᴍᴇʀ Wᴏʟʙᴇʀɢ 2018-06-22 11:42:34

Il n'est pas possible de trouver la valeur sizeof du pointeur, car le compilateur ne sait pas combien de temps ce pointeur est poiting. Le pointeur sizeof doit être 2 ou 4 (selon le compilateur).

-1
répondu Jeyamaran 2015-07-14 22:55:18

Salut dans les chaînes il y a un caractère '\0' à la fin donc on peut obtenir la taille d'une chaîne avec des fonctions comme strlen le problème avec un tableau entier par exemple est que u ne peut utiliser aucune valeur comme valeur de fin, donc une solution possible est d'adresser le tableau et d'utiliser comme valeur de fin le pointeur NULL

/* http://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array */
#include <stdio.h>
/* the following function will produce the warning:
 * ‘sizeof’ on array function parameter ‘a’ will
 * return size of ‘int *’ [-Wsizeof-array-argument]
 */
void foo( int a[] )
{
    printf( "%lu\n", sizeof a );
}
/* so we have to implement something else one possible
 * idea is to use the NULL pointer as a control value
 * the same way '\0' is used in strings but this way
 * the pointer passed to a function should address pointers
 * so the actual implementation of an array type will
 * be a pointer to pointer
 */
typedef char * type_t; /* line 18 */
typedef type_t ** array_t;
/*
 *    -- --
 *   -**-**-
 *   -$$$$$-
 *    -999-
 *     -^-
 *      -
 */
int main( void )
{
    array_t initialize( int, ... );
    /* initialize an array with four values "foo", "bar", "baz", "foobar"
     * if one wants to use integers rather than strings than in the typedef
     * declaration at line 18 the char * type should be changed with int
     * and in the format used for printing the array values 
     * at line 45 and 51 "%s" should be changed with "%i"
     */
    array_t array = initialize( 4, "foo", "bar", "baz", "foobar" );

    int size( array_t );
    /* print array size */
    printf( "size %i:\n", size( array ));

    void aprint( char *, array_t );
    /* print array values */
    aprint( "%s\n", array ); /* line 45 */

    type_t getval( array_t, int );
    /* print an indexed value */
    int i = 2;
    type_t val = getval( array, i );
    printf( "%i: %s\n", i, val ); /* line 51 */

    void delete( array_t );
    /* free some space */
    delete( array );

    return 0;
}
/* the output of the program should be:
 * size 4:
 * foo
 * bar
 * baz
 * foobar
 * 2: baz
 */
#include <stdarg.h>
#include <stdlib.h>
array_t initialize( int n, ... )
{
    /* here we store the array values */
    type_t *v = (type_t *) malloc( sizeof( type_t ) * n );
    va_list ap;
    va_start( ap, n );
    int j;
    for ( j = 0; j < n; j++ )
        v[j] = va_arg( ap, type_t );
    va_end( ap );
    /* the actual array will hold the addresses of those
     * values plus a NULL pointer
     */
    array_t a = (array_t) malloc( sizeof( type_t *) * ( n + 1 ));
    a[n] = NULL;
    for ( j = 0; j < n; j++ )
        a[j] = v + j;
    return a;
}
int size( array_t a )
{
    int n = 0;
    while ( *a++ != NULL )
        n++;
    return n;
}
void aprint( char *fmt, array_t a )
{
    while ( *a != NULL )
        printf( fmt, **a++ );   
}
type_t getval( array_t a, int i )
{
    return *a[i];
}
void delete( array_t a )
{
    free( *a );
    free( a );
}
/* край */
-1
répondu baz 2017-03-12 06:34:17