繁体   English   中英

sizeof(arr) / sizeof(arr[0]) 是如何工作的?

[英]How do sizeof(arr) / sizeof(arr[0]) work?

在 for 循环中寻找数组的大小时,我看到人们写

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

sizeof(arr) / sizeof(arr[0])数组的长度是多少? 它在技术上如何运作?

如果您有一个arraysizeof(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 条),要么是一个带括号的类型 ID。

在这个表达式中

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

这是一个简单的关系。 如果你有一个 T 类型的 N 个元素的数组

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 个字节,具体取决于使用的环境。 你不会得到元素的数量。 你会得到一些奇怪的值。

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,就是数组的长度。

它仅在arr没有衰减为指针时才有效,即它是数组类型,而不是指针类型。

sizeof(arr)是数组占用的总大小。

sizeof(arr[0])是数组中第一个元素的大小。 (请注意,C++ 中不允许零长度数组,因此如果数组本身存在,则该元素始终存在)。

由于所有元素的大小相同,因此元素数量为sizeof(arr) / sizeof(arr[0])

处理数组( some_type name[some_size] )时, sizeof(name)是数组占用的字节数。 将数组的总大小除以一个元素的大小 ( sizeof(name[0]) ) 得出数组中有多少个元素。

c++ 使用范围的方式,它允许您获取数组第 N 维中的多个元素。 有关详细信息,请参阅http://en.cppreference.com/w/cpp/types/extent

int values[] = { 1 };

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

让我们举个例子,比如arr[]={1,2,4,3,5}

那么数组的大小将是 5 并且arr[0]的大小将是“1”,因为它包含一个元素。 基本上它是一个子数组,从上面的问题来看,它将是 5/1,它将自动返回数组的大小 =5。

区别在于 int arr[5] = {1,2,3,4,5}; 这里arr是指向数组的指针&arr[0]是Integer类型的指针

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM