Question

Comment déterminer la taille de mon tableau en C ?

C'est-à-dire le nombre d'éléments que le tableau peut contenir ?

Était-ce utile?

La solution

Résumé exécutif:

int a[17];
size_t n = sizeof(a)/sizeof(a[0]);

Réponse complète :

Pour déterminer la taille de votre tableau en octets, vous pouvez utiliser le sizeofopérateur:

int a[17];
size_t n = sizeof(a);

Sur mon ordinateur, les entiers font 4 octets, donc n vaut 68.

Pour déterminer le nombre d'éléments dans le tableau, nous pouvons diviser la taille totale du tableau par la taille de l'élément de tableau.Vous pouvez faire cela avec le type, comme ceci :

int a[17];
size_t n = sizeof(a) / sizeof(int);

et obtenez la bonne réponse (68 / 4 = 17), mais si le type dea changé, vous auriez un bogue méchant si vous oubliiez de changer le sizeof(int) aussi.

Le diviseur préféré est donc sizeof(a[0]), la taille de l'élément Zeroeth du tableau.

int a[17];
size_t n = sizeof(a) / sizeof(a[0]);

Un autre avantage est que vous pouvez désormais paramétrer facilement le nom du tableau dans une macro et obtenir:

#define NELEMS(x)  (sizeof(x) / sizeof((x)[0]))

int a[17];
size_t n = NELEMS(a);

Autres conseils

Le sizeof la voie est la bonne voie si et si vous avez affaire à des tableaux non reçus en paramètres.Un tableau envoyé en paramètre à une fonction est traité comme un pointeur, donc sizeof renverra la taille du pointeur, au lieu de celle du tableau.

Ainsi, à l’intérieur des fonctions, cette méthode ne fonctionne pas.Au lieu de cela, transmettez toujours un paramètre supplémentaire size_t size indiquant le nombre d'éléments dans le tableau.

Test:

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

void printSizeOf(int intArray[]);
void printLength(int intArray[]);

int main(int argc, char* argv[])
{
    int array[] = { 0, 1, 2, 3, 4, 5, 6 };

    printf("sizeof of array: %d\n", (int) sizeof(array));
    printSizeOf(array);

    printf("Length of array: %d\n", (int)( sizeof(array) / sizeof(array[0]) ));
    printLength(array);
}

void printSizeOf(int intArray[])
{
    printf("sizeof of parameter: %d\n", (int) sizeof(intArray));
}

void printLength(int intArray[])
{
    printf("Length of parameter: %d\n", (int)( sizeof(intArray) / sizeof(intArray[0]) ));
}

Sortie (dans un système d'exploitation Linux 64 bits) :

sizeof of array: 28
sizeof of parameter: 8
Length of array: 7
Length of parameter: 2

Sortie (dans un système d'exploitation Windows 32 bits) :

sizeof of array: 28
sizeof of parameter: 4
Length of array: 7
Length of parameter: 1

Il est à noter que sizeof n'aide pas lorsqu'il s'agit d'une valeur de tableau qui s'est décomposée en un pointeur :même s'il pointe vers le début d'un tableau, pour le compilateur, c'est la même chose qu'un pointeur vers un seul élément de ce tableau.Un pointeur ne « se souvient » de rien d’autre sur le tableau qui a été utilisé pour l’initialiser.

int a[10];
int* p = a;

assert(sizeof(a) / sizeof(a[0]) == 10);
assert(sizeof(p) == sizeof(int*));
assert(sizeof(*p) == sizeof(int));

La taille du "truc" est la meilleure façon que je connaisse, avec un changement petit mais important (pour moi, c'est une bête noire majeure) dans l'utilisation des parenthèses.

Comme l'indique clairement l'entrée Wikipédia, C's sizeof n'est pas une fonction ;c'est un opérateur.Ainsi, il ne nécessite pas de parenthèses autour de son argument, sauf si l'argument est un nom de type.C'est facile à retenir, car cela donne à l'argument l'apparence d'une expression castée, qui utilise également des parenthèses.

Donc:Si vous disposez des éléments suivants :

int myArray[10];

Vous pouvez trouver le nombre d'éléments avec un code comme celui-ci :

size_t n = sizeof myArray / sizeof *myArray;

Cela, pour moi, se lit beaucoup plus facilement que l'alternative entre parenthèses.Je privilégie également l'utilisation de l'astérisque dans la partie droite de la division, car c'est plus concis que l'indexation.

Bien sûr, tout cela est également au moment de la compilation, vous n'avez donc pas à vous soucier de la division affectant les performances du programme.Utilisez donc ce formulaire partout où vous le pouvez.

Il est toujours préférable d'utiliser sizeof sur un objet réel lorsque vous en avez un, plutôt que sur un type, car vous n'avez alors pas à vous soucier de faire une erreur et d'indiquer le mauvais type.

Par exemple, disons que vous disposez d'une fonction qui génère certaines données sous forme de flux d'octets, par exemple sur un réseau.Appelons la fonction send(), et lui faire prendre comme arguments un pointeur vers l'objet à envoyer, et le nombre d'octets dans l'objet.Le prototype devient donc :

void send(const void *object, size_t size);

Et puis vous devez envoyer un entier, donc vous le codez comme ceci :

int foo = 4711;
send(&foo, sizeof (int));

Maintenant, vous avez introduit une manière subtile de se tirer une balle dans le pied, en précisant le type de foo à deux endroits.Si l’un change mais pas l’autre, le code se casse.Ainsi, procédez toujours comme ceci :

send(&foo, sizeof foo);

Maintenant, vous êtes protégé.Bien sûr, vous dupliquez le nom de la variable, mais cela a une forte probabilité d'être interrompu d'une manière que le compilateur peut détecter, si vous le modifiez.

int size = (&arr)[1] - arr;

Vérifier ce lien pour explication

Vous pouvez utiliser l'opérateur SizeOf mais il ne fonctionnera pas pour les fonctions car il prendra la référence du pointeur que vous pouvez effectuer ce qui suit pour trouver la longueur d'un tableau:

len = sizeof(arr)/sizeof(arr[0])

Code trouvé à l'origine ici :Programme C pour trouver le nombre d'éléments dans un tableau

Si vous connaissez le type de données du tableau, vous pouvez utiliser quelque chose comme :

int arr[] = {23, 12, 423, 43, 21, 43, 65, 76, 22};

int noofele = sizeof(arr)/sizeof(int);

Ou si vous ne connaissez pas le type de données du tableau, vous pouvez utiliser quelque chose comme :

noofele = sizeof(arr)/sizeof(arr[0]);

Note:Cette chose ne fonctionne que si le tableau n'est pas défini au moment de l'exécution (comme malloc) et que le tableau n'est pas transmis dans une fonction.Dans les deux cas, arr (nom du tableau) est un pointeur.

La macro ARRAYELEMENTCOUNT(x) que tout le monde utilise les évaluations incorrectement.En réalité, c'est juste une question sensible, car vous ne pouvez pas avoir d'expressions qui aboutissent à un type « tableau ».

/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x[0]))

ARRAYELEMENTCOUNT(p + 1);

En fait s'évalue comme :

(sizeof (p + 1) / sizeof (p + 1[0]));

Alors que

/* Compile as: CL /P "macro.c" */
# define ARRAYELEMENTCOUNT(x) (sizeof (x) / sizeof (x)[0])

ARRAYELEMENTCOUNT(p + 1);

Il évalue correctement :

(sizeof (p + 1) / sizeof (p + 1)[0]);

Cela n’a vraiment pas grand chose à voir explicitement avec la taille des tableaux.Je viens de remarquer beaucoup d'erreurs dues au fait de ne pas vraiment observer le fonctionnement du préprocesseur C.Vous encapsulez toujours le paramètre de macro, et aucune expression ne peut y être impliquée.


C'est correct;mon exemple était mauvais.Mais c’est exactement ce qui devrait arriver.Comme je l'ai mentionné précédemment p + 1 finira par être un type de pointeur et invalidera la macro entière (comme si vous tentiez d'utiliser la macro dans une fonction avec un paramètre de pointeur).

En fin de compte, dans ce particulier par exemple, la faute n'a pas vraiment d'importance (donc je fais juste perdre le temps à tout le monde ;huzzah !), car vous n'avez pas d'expressions avec un type de « tableau ».Mais je pense que le point concernant les subtilités de l’évaluation du préprocesseur est vraiment important.

Pour tableaux multidimensionnels c'est un peu plus compliqué.Souvent, les gens définissent des constantes macro explicites, c'est-à-dire

#define g_rgDialogRows   2
#define g_rgDialogCols   7

static char const* g_rgDialog[g_rgDialogRows][g_rgDialogCols] =
{
    { " ",  " ",    " ",    " 494", " 210", " Generic Sample Dialog", " " },
    { " 1", " 330", " 174", " 88",  " ",    " OK",        " " },
};

Mais ces constantes peuvent également être évaluées au moment de la compilation avec taille de:

#define rows_of_array(name)       \
    (sizeof(name   ) / sizeof(name[0][0]) / columns_of_array(name))
#define columns_of_array(name)    \
    (sizeof(name[0]) / sizeof(name[0][0]))

static char* g_rgDialog[][7] = { /* ... */ };

assert(   rows_of_array(g_rgDialog) == 2);
assert(columns_of_array(g_rgDialog) == 7);

Notez que ce code fonctionne en C et C++.Pour les tableaux à plus de deux dimensions, utilisez

sizeof(name[0][0][0])
sizeof(name[0][0][0][0])

etc., à l'infini.

Taille d'un tableau en C :

int a[10];
size_t size_of_array = sizeof(a);      // Size of array a
int n = sizeof (a) / sizeof (a[0]);    // Number of elements in array a
size_t size_of_element = sizeof(a[0]); // Size of each element in array a                                          
                                       // Size of each element = size of type
sizeof(array) / sizeof(array[0])
#define SIZE_OF_ARRAY(_array) (sizeof(_array) / sizeof(_array[0]))

"vous avez introduit une manière subtile de vous tirer une balle dans le pied"

Les tableaux « natifs » C ne stockent pas leur taille.Il est donc recommandé de sauvegarder la longueur du tableau dans une variable/const distincte et de la transmettre à chaque fois que vous transmettez le tableau, c'est-à-dire :

#define MY_ARRAY_LENGTH   15
int myArray[MY_ARRAY_LENGTH];

Vous DEVRIEZ toujours éviter les tableaux natifs (sauf si vous ne pouvez pas, auquel cas faites attention à votre pied).Si vous écrivez en C++, utilisez le STLLe conteneur « vecteur »."Par rapport aux baies, ils offrent presque les mêmes performances", et ils sont bien plus utiles !

// vector is a template, the <int> means it is a vector of ints
vector<int> numbers;  

// push_back() puts a new value at the end (or back) of the vector
for (int i = 0; i < 10; i++)
    numbers.push_back(i);

// Determine the size of the array
cout << numbers.size();

Voir:http://www.cplusplus.com/reference/stl/vector/

@Magnus :La norme définit sizeof comme donnant le nombre d'octets dans l'objet et que sizeof (char) est toujours un.Le nombre de bits dans un octet dépend de l'implémentation.

Modifier:Section 5.3.3 de la norme ANSI C++

L'opérateur sizeof donne le nombre d'octets dans la représentation objet de son opérande.[...] sizeof (char), sizeof (signed char) et sizeof (unsigned char) sont 1;le résultat de sizeof appliqué à tout autre type fondamental est défini par l’implémentation.

Section 1.6 Le modèle de mémoire C++ :

L'unité de stockage fondamentale dans le modèle de mémoire C++ est l'octet.Un octet est au moins suffisamment grand pour contenir n'importe quel membre du jeu de caractères d'exécution de base et est composé d'une séquence contiguë de bits, dont le nombre est défini par l'implémentation.

@Skizz :Je suis presque sûr d'avoir raison, même si la meilleure "source" que je puisse vous donner pour le moment est Wikipédia, d'après l'article sur sizeof :

Wikipédia a tort, Skizz a raison.sizeof(char) est 1, par définition.

Je veux dire, il suffit de lire très attentivement l'entrée Wikipédia pour voir que c'est faux."multiples de caractères". sizeof(char) ne pourra jamais être quelque chose autre que "1".Si c'était, disons, 2, cela voudrait dire que sizeof(char) était deux fois plus gros qu'un omble chevalier !

Si vous voulez vraiment faire cela pour faire circuler votre tableau, je suggère d'implémenter une structure pour stocker un pointeur vers le type dont vous voulez un tableau et un entier représentant la taille du tableau.Ensuite, vous pouvez transmettre cela à vos fonctions.Attribuez simplement la valeur de la variable du tableau (pointeur vers le premier élément) à ce pointeur.Alors tu peux y aller Array.arr[i] pour obtenir le i-ième élément et utiliser Array.size pour obtenir le nombre d'éléments dans le tableau.

J'ai inclus du code pour vous.Ce n'est pas très utile mais vous pouvez l'étendre avec plus de fonctionnalités.Pour être honnête cependant, si ce sont les choses que vous souhaitez, vous devriez arrêter d'utiliser C et utiliser un autre langage avec ces fonctionnalités intégrées.

/* Absolutely no one should use this...
   By the time you're done implementing it you'll wish you just passed around
   an array and size to your functions */
/* This is a static implementation. You can get a dynamic implementation and 
   cut out the array in main by using the stdlib memory allocation methods,
   but it will work much slower since it will store your array on the heap */

#include <stdio.h>
#include <string.h>
/*
#include "MyTypeArray.h"
*/
/* MyTypeArray.h 
#ifndef MYTYPE_ARRAY
#define MYTYPE_ARRAY
*/
typedef struct MyType
{
   int age;
   char name[20];
} MyType;
typedef struct MyTypeArray
{
   int size;
   MyType *arr;
} MyTypeArray;

MyType new_MyType(int age, char *name);
MyTypeArray newMyTypeArray(int size, MyType *first);
/*
#endif
End MyTypeArray.h */

/* MyTypeArray.c */
MyType new_MyType(int age, char *name)
{
   MyType d;
   d.age = age;
   strcpy(d.name, name);
   return d;
}

MyTypeArray new_MyTypeArray(int size, MyType *first)
{
   MyTypeArray d;
   d.size = size;
   d.arr = first;
   return d;
}
/* End MyTypeArray.c */


void print_MyType_names(MyTypeArray d)
{
   int i;
   for (i = 0; i < d.size; i++)
   {
      printf("Name: %s, Age: %d\n", d.arr[i].name, d.arr[i].age);
   }
}

int main()
{
   /* First create an array on the stack to store our elements in.
      Note we could create an empty array with a size instead and
      set the elements later. */
   MyType arr[] = {new_MyType(10, "Sam"), new_MyType(3, "Baxter")};
   /* Now create a "MyTypeArray" which will use the array we just
      created internally. Really it will just store the value of the pointer
      "arr". Here we are manually setting the size. You can use the sizeof
      trick here instead if you're sure it will work with your compiler. */
   MyTypeArray array = new_MyTypeArray(2, arr);
   /* MyTypeArray array = new_MyTypeArray(sizeof(arr)/sizeof(arr[0]), arr); */
   print_MyType_names(array);
   return 0;
}

La meilleure façon est de sauvegarder ces informations, par exemple, dans une structure :

typedef struct {
     int *array;
     int elements;
} list_s;

Implémentez toutes les fonctions nécessaires telles que créer, détruire, vérifier l'égalité et tout ce dont vous avez besoin.Il est plus facile de passer en paramètre.

La fonction sizeof renvoie le nombre d'octets utilisés par votre tableau dans la mémoire.Si vous souhaitez calculer le nombre d'éléments de votre tableau, vous devez diviser ce nombre par le sizeof type de variable du tableau.Disons int array[10];, si le type de variable entier sur votre ordinateur est de 32 bits (ou 4 octets), afin d'obtenir la taille de votre tableau, vous devez procéder comme suit :

int array[10];
int sizeOfArray = sizeof(array)/sizeof(int);

Vous pouvez utiliser le & opérateur.Voici le code source :

#include<stdio.h>
#include<stdlib.h>
int main(){

    int a[10];

    int *p; 

    printf("%p\n", (void *)a); 
    printf("%p\n", (void *)(&a+1));
    printf("---- diff----\n");
    printf("%zu\n", sizeof(a[0]));
    printf("The size of array a is %zu\n", ((char *)(&a+1)-(char *)a)/(sizeof(a[0])));


    return 0;
};

Voici l'exemple de sortie

1549216672
1549216712
---- diff----
4
The size of array a is 10
int a[10];
int size = (*(&a+1)-a) ;

Pour plus de détails, voiriciet aussi ici.

Exemple

#include <stdio.h>

int main() {
    int size;
    scanf("%d", &size);
    int array[size];
    printf("%d\n", (int) (sizeof(array) / sizeof(int)));
    printf("%d\n", (int) (sizeof(array) / sizeof(array[0])));
    return 0;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top