【问题标题】:Why does the sizeof operator produce different results for an array为什么 sizeof 运算符对数组产生不同的结果
【发布时间】:2021-04-16 12:30:24
【问题描述】:

为什么sizeof 操作符在应该只有 4 个字节时却产生了 12 个字节?当我引用变量array 时,那只是指数组第一个索引的内存地址。实际上,我打印了第一个索引&array[0] 的内存地址并将其与array 进行比较,它们产生了相同的内存地址结果,这证实它们都引用了数组的第一个索引,但是'array'产生12 字节,而 array[0] 产生 4 字节。

int main() {
int array[] = {1,2,3};
int a = 1;
int b = sizeof(array); //this is referring to the first index of the array
int c = sizeof(array[0]); //this is also referring to the first index of the array

std::cout << b << std::endl;
std::cout << array << std::endl; //they have the same memory address
std::cout << &array[0] << std::endl; /* they have the same memory address, which confirms that array 
and &array[0] is the same */

return 0;
}

【问题讨论】:

  • sizeof(array); //this is referring to the first index of the array 你为什么这么认为? array 是数组的名称。数组大小是其元素数量乘以元素大小。
  • array -> int[3]array[0] -> int
  • 如果foo 是一个函数,那么表达式foo(array) 中的array 衰减为指向其第一个元素的指针。但是sizeof(array) 不是函数调用。您可以使用成语sizeof array 提醒自己这一事实。省略括号时,将sizeof 与函数调用混淆起来要困难得多。
  • 大多数上下文中,数组的名称衰减为指向其第一个元素的指针。 sizeof 是例外之一; array 指的是整个数组,它有3个int类型的元素。

标签: c++ c


【解决方案1】:

数组和指针不一样,这是一个很好的例子。

大多数上下文中,数组衰减为指向其第一个成员的指针。当数组是sizeof 运算符的主题时,这种衰减不会发生的少数情况之一。在这种情况下,它引用 整个 数组,表达式的计算结果是整个数组的大小(以字节为单位)。

这在C standard 的第 6.3.2.1p3 节中有描述:

除非它是sizeof 运算符、_Alignof 运算符或一元&amp; 运算符的操作数,或者是用于初始化数组的字符串文字,否则表达式类型为“array of type”转换为类型为“pointer to type”的表达式,它指向数组对象的初始元素,而不是左值。如果数组对象有注册存储类,则行为未定义。

以及第 7.2 节中的 C++11 标准:

“N T 的数组”或“T 的未知边界数组”类型的左值或右值可以转换为“指向 T 的指针”类型的纯右值。应用了临时实现转换 (7.4)。结果是指向数组第一个元素的指针。

还有 8.3.3p4:

左值到右值 (7.1)、数组到指针 (7.2) 和函数到指针 (7.3) 标准转换不适用于 sizeof 的操作数。如果操作数是纯右值,则应用临时实现转换 (7.4)。

所以我们实际上拥有的是:

int b = sizeof(array);     // size of the entire array
int c = sizeof(array[0]);  // size of the first element of the array
int d = sizeof(&array[0]); // size of a pointer to an array element

【讨论】:

    【解决方案2】:

    数组的大小 12 个字节。输出是正确的。元素的大小为 4 个字节。有3个元素。 4 * 3 = 12。

    实际上,我打印了第一个索引 (&array[0]) 的内存地址并将其与 (array) 进行比较,它们产生了相同的内存地址结果,这证实它们都引用了数组的第一个索引

    仅仅因为数组与数组的第一个元素具有相同的内存地址,并不意味着整个数组都包含在第一个元素中。不是。


    那为什么array+1 指的是数组的第二个索引呢?

    因为在这样的子表达式中,数组被隐式转换为指向第一个元素的指针,将指向第一个元素的指针加 1 会得到指向第二个元素的指针。这种隐式转换称为衰减。

    【讨论】:

    • 我以为没有办法选择整个数组?当我们调用变量数组时,我认为它只会引用第一个索引
    • @RenzCarillo “调用”数组是什么意思。
    • @RenzCarillo 与 VLA 扩展一起(假设 C++,在 C 中它是标准的可选部分,在 C99 中是强制性的)还可以检查 VLA 的大小,但它发生在运行时。
    • int 数组[]; //我们正在调用数组
    • @RenzCarillo 数组不同于指向数组第一个元素的指针。这两个很容易混淆,因为数组真的很喜欢变成指向它们的第一个元素的指针。数组类型的函数参数进一步加剧了混乱,这些函数参数继承自 C,非常糟糕,实际上是变相的指针。但实际上array在这里没有理由变成指针,所以这里是整个int[3]的名称,而不是int*的名称。
    【解决方案3】:

    如果我很好地理解了您的问题,在 64 位机器上 int 将是 4 个字节,因此 sizeof 运算符将返回 3 x 4 = 12 个字节。不明白您的假设为什么当您在该数组中仅分配三个项目时它应该首先返回 4。

    如果您想知道数组中的项目数,您可以执行以下操作:

    // 查找数组[] 的大小并存储在 'size' 中 int size = sizeof(array)/sizeof(array[0]);

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-05
      • 2020-01-10
      • 2014-08-22
      • 1970-01-01
      • 2011-08-11
      • 1970-01-01
      • 2020-11-09
      • 2019-08-12
      相关资源
      最近更新 更多