Когда вы ищете размер массива в цикле for, я видел, как люди пишут
int arr[10];
for(int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){}
Как 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])
длина массива? Как это технически работает?
Если у вас есть 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()
Как описано в C++ Standard (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.
Примите в acccount что обычно новички делают такую ошибку. Они передают массив как аргумент функции. Например, предположим, что у вас есть функция
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, и это длина массива.