Как работает sizeof(arr) / sizeof (arr[0])?

при поиске размера массива в цикле for я видел, как люди пишут

int arr[10];
for(int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){}

Как sizeof(arr) / sizeof(arr[0]) длина массива? Как это технически работает?

6 ответов


если у вас array затем sizeof(array) возвращает количество байтов, которое занимает массив. Поскольку каждый элемент может занимать более 1 байта пространства, вы должны разделить результат на размер одного элемента (sizeof(array[0])). Это дает вам количество элементов в массиве.

пример:

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

ЖИВОЙ ПРИМЕР

обратите внимание, что если вы передаете массив в функцию, выше не сработает, так как массив распадается на указатель и sizeof(array) возвращает размер указателя.

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()

ЖИВОЙ ПРИМЕР #2


как описано в стандарте C++ (5.3.3 Sizeof)

1 оператор sizeof возвращает количество байтов в объекте представление его операнда. Операнд является выражением, который является недооцененным операндом (пункт 5) или заключенным в скобки тип-идентификатор.

в этом выражении

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

используются два подвыражения с оператором sizeof.

этот подвыражение

sizeof(arr)

дает количество байтов, занятых массивом arr (я полагаю, что arr массив).

например, если вы объявили массив типа

int arr[10];

затем компилятор должен зарезервировать память, чтобы удерживать 10 элементов типа int. Если, например,sizeof( int ) равно 4, тогда компилятор зарезервирует 10 * 4 = 40 байт памяти.

подвыражения

sizeof(arr[0])

дает количество байтов занято одним элементом массива. Вы можете использовать любой индекс, например

sizeof(arr[1000])

потому что выражение не оценено. Важно только размер в байтах объекта (элемента массива) используется внутри оператора.

таким образом, если вы знаете общее количество байтов, зарезервированных для массива

sizeof(arr)

и знать, сколько байтов занимает каждый элемент массива (все элементы массива имеют одинаковый размер), то вы можете вычислить количество элементов в массиве с помощью формулы

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

вот простое соотношение. Если у вас есть массив из n элементов типа T

T arr[N];

а вы знаете размер памяти, занимаемой массивом, то вы можете рассчитать размер своего элемента, используя формулу

sizeof( arr ) / N == size of an element of the array. 

и наоборот

если вы знаете размер памяти, занимаемой массивом и размер его элемента можно вычислить количество элементов в массив

sizeof( arr ) / sizeof( a[0] ) == N - number of elements in the array

последнее выражение можно переписать также следующим образом

sizeof( arr ) / sizeof( T ) == N - number of elements in the array

потому что элементы массива имеют тип T и каждый элемент массива занимает ровно то количество байтов, которое требуется для выделения объекта типа T.

примите во внимание, что обычно новички делают такую ошибку. Они передают массив в качестве аргумента функции. Например предположим, что у вас есть функция

void f( int a[] )
{
   // ...
}

и передать в функцию массив

int arr[10];
f(arr);

затем функция использует указатель на первый элемент массива. На самом деле функция имеет объявление

void f( int *a )
{
   // ...
}

Итак, если вы пишете, например, в функции

void f( int *a )
{
   size_t n = sizeof( a ) / sizeof( a[0] );
   // ...
}

тогда как a внутри функции указатель (не массив), то вы получите что-то вроде

void f( int *a )
{
   size_t n = sizeof( int * ) / sizeof( int );
   // ...
}

обычно размер указателя равен 8 или 4 байта в зависимости от используемой среды. И вы не получите количество элементов. Вы получите какую-то странную ценность.


это работает только если arr не распадается на указатель, то есть это тип массива, не тип указателя.

sizeof(arr) - общий размер, занимаемый массивом.

sizeof(arr[0]) - размер первого элемента в массиве. (Обратите внимание, что массивы нулевой длины запрещены в C++, поэтому этот элемент всегда существует, если сам массив существует).

так как все элементы будут одинакового размера, количество элементов sizeof(arr) / sizeof(arr[0]).


при работе с массивом (some_type name[some_size]) sizeof(name) - Это сколько байтов занимает массив. Деление общего размера массива на размер одного элемента (sizeof(name[0])) дает вам, сколько элементов в массиве.


C++ способ использования экстента, который позволяет u получить ряд элементов в N-м измерении массива. см.http://en.cppreference.com/w/cpp/types/extent для деталей

int values[] = { 1 };

std::extent<decltype(values)>::value == 1

int - равно 4 байтам
sizeof(int) это означает: 1 * 4 = 4

int arr[10] - держит 10 int
sizeof(arr) это означает: 10 * 4 = 40, мы получили 10 int и все int есть 4 байта,, arr без [] это означает, что все arr.

sizeof(arr[0]) это означает: 1 * 4 = 4

sizeof(arr) / sizeof(arr[0]) = 10*4 / 1*4 = 10,, и это длина массива.