Lors de la recherche de la taille d'un tableau dans une boucle for, j'ai vu des gens écrire
int arr[10];
for(int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){}
Comment sizeof(arr) / sizeof(arr[0])
est-il la longueur du tableau? Comment ça marche techniquement?
Si vous avez une array
, alors sizeof(array)
renvoie le nombre d'octets occupés par le tableau. Étant donné que chaque élément peut occuper plus d'un octet, vous devez diviser le résultat par la taille d'un élément (sizeof(array[0])
). Cela vous donne le nombre d'éléments dans le tableau.
Exemple:
std::uint32_t array[10];
auto sizeOfInt = sizeof(std::uint32_t); // 4
auto numOfBytes = sizeof(array); // 10*sizeOfInt = 40
auto sizeOfElement = sizeof(array[0]); // sizeOfInt = 4
auto numOfElements = sizeof(array) / sizeof(array[0]); // numOfBytes / sizeOfElement = 40 / 4 = 10
Notez que si vous transmettez un tableau à une fonction, cela ne fonctionnera pas, car le tableau se décompose en un pointeur et sizeof(array)
renvoie la taille du pointeur.
std::size_t function(std::uint32_t a[]) // same for void function(std::uint32_t a[10])
{
return sizeof(a); // sizeof(std::uint32_t*)!
}
std::uint32_t array[10];
auto sizeOfArray = function(array); // array decays to a pointer inside function()
Comme décrit dans la norme C++ (5.3.3 Sizeof)
1 L'opérateur sizeof donne le nombre d'octets de l'objet représentation de son opérande. L'opérande est soit une expression, qui est un opérande non évalué (clause 5) ou une parenthèse type-id.
Dans cette expression
sizeof(arr) / sizeof(arr[0])
on utilise deux sous-expressions avec l'opérateur sizeof.
Cette sous-expression
sizeof(arr)
donne le nombre d'octets occupés par le tableau arr
(je suppose que arr
est un tableau).
Par exemple, si vous avez déclaré un tableau comme
int arr[10];
alors le compilateur doit réserver de la mémoire pour contenir 10 éléments de type int. Si, par exemple, sizeof( int )
est égal à 4, le compilateur réservera 10 * 4 = 40 octets de mémoire.
Sous expression
sizeof(arr[0])
donne le nombre d'octets occupés par un élément du tableau. Vous pouvez utiliser n'importe quel index comme par exemple
sizeof(arr[1000])
parce que l'expression n'est pas évaluée. La taille en octets de l'objet (un élément du tableau) utilisé dans l'opérateur est importante.
Donc, si vous connaissez le nombre total d'octets réservés pour un tableau
sizeof(arr)
et savoir combien d'octets chaque élément du tableau occupe (tous les éléments d'un tableau ont la même taille), vous pouvez alors calculer le nombre d'éléments dans le tableau en utilisant la formule
sizeof(arr) / sizeof(arr[0])
Voici une relation simple. Si vous avez un tableau de N éléments de type T
T arr[N];
et vous connaissez la taille de la mémoire occupée par le tableau, alors vous pouvez calculer la taille de son élément en utilisant la formule
sizeof( arr ) / N == size of an element of the array.
Et vice versa
Si vous connaissez la taille de la mémoire occupée par le tableau et la taille de son élément, vous pouvez calculer le nombre d'éléments dans le tableau.
sizeof( arr ) / sizeof( a[0] ) == N - number of elements in the array
La dernière expression que vous pouvez réécrire aussi de la manière suivante
sizeof( arr ) / sizeof( T ) == N - number of elements in the array
parce que les éléments du tableau ont le type T et que chaque élément du tableau occupe exactement le nombre d'octets requis pour allouer un objet de type T.
Tenez compte du fait que ce sont généralement les débutants qui font une telle erreur. Ils passent un tableau en tant qu'argument à une fonction. Par exemple, supposons que vous ayez une fonction
void f( int a[] )
{
// ...
}
Et vous passez à la fonction votre tableau
int arr[10];
f(arr);
alors la fonction utilise le pointeur sur le premier élément du tableau. En fait, la fonction a une déclaration
void f( int *a )
{
// ...
}
Donc, si vous écrivez par exemple dans la fonction
void f( int *a )
{
size_t n = sizeof( a ) / sizeof( a[0] );
// ...
}
alors comme a
dans la fonction est un pointeur (ce n'est pas un tableau), alors vous obtiendrez quelque chose comme
void f( int *a )
{
size_t n = sizeof( int * ) / sizeof( int );
// ...
}
Généralement, la taille d'un pointeur est égale à 8 ou 4 octets, en fonction de l'environnement utilisé. Et vous n'obtiendrez pas le nombre d'éléments. Vous obtiendrez une valeur étrange.
Cela ne fonctionne que si arr
n'a pas été décomposé en pointeur, c'est-à-dire qu'il s'agit d'un type de tableau, pas un type de pointeur.
sizeof(arr)
est la taille totale occupée par le tableau.
sizeof(arr[0])
est la taille du premier élément du tableau. (Notez que les tableaux de longueur nulle ne sont pas autorisés en C++, donc cet élément existe toujours si le tableau lui-même existe).
Comme tous les éléments auront la même taille, le nombre d’éléments est sizeof(arr) / sizeof(arr[0])
.
int
- est égal à 4 octetssizeof(int)
cela signifie: 1 * 4 = 4
int arr[10]
- tient 10 int
sizeof(arr)
cela signifie: 10 * 4 = 40, nous avons 10 int
et chaque int
a 4 octets , arr
sans le []
cela signifie toute la arr
.
sizeof(arr[0])
cela signifie: 1 * 4 = 4
sizeof(arr) / sizeof(arr[0])
= 10 * 4/1 * 4 = 10 , et c'est la longueur du tableau.
Lorsqu’il s’agit d’un tableau (some_type name[some_size]
), sizeof(name)
est le nombre d’octets qu’il occupe. En divisant la taille totale du tableau par la taille d'un élément (sizeof(name[0])
), vous obtenez le nombre d'éléments contenus dans le tableau.
c ++ manière d’utiliser l’extension, ce qui vous permet d’obtenir un certain nombre d’éléments dans la Nième dimension du tableau . voir http://fr.cppreference.com/w/cpp/types/extent pour plus de détails.
int values[] = { 1 };
std::extent<decltype(values)>::value == 1