通过指针算法计算数组长度

我想知道*(&array + 1)实际上是如何工作的。 我认为这是一种计算数组长度的简单方法,并希望在使用之前正确理解它。 我对指针算法不太熟悉,但是我的理解&array给出了&array第一个元素的地址。 (&array + 1)将根据地址到达数组的末尾。 但不应该*(&array + 1)给出该地址的值。 而是打印出地址。 我非常感谢你的帮助,让我的脑袋里的指针清晰。

这是我正在研究的简单示例:

 int numbers[] = {5,8,9,3,4,6,1}; int length = *(&numbers + 1) - numbers; 

(这个答案适用于C ++。)

  1. &numbers是指向数组本身的指针。 它的类型为int (*)[7]
  2. &numbers + 1是指向数组后面的字节的指针,其中将定位另一个7 int的数组。 它仍然具有类型int (*)[7]
  3. *(&numbers + 1)取消引用此指针,产生一个int[7]类型的左值,指向数组后面的字节。
  4. *(&numbers + 1) - numbers :使用-运算符强制两个操作数进行数组到指针的转换,因此可以减去指针。 *(&numbers + 1)转换为指向数组后面的字节的int*numbers转换为指向数组第一个字节的int* 。 它们的区别在于两个指针之间的int数 – 这是数组中int的数量。

编辑:虽然&numbers + 1没有指向有效对象,但这就是所谓的“过去结束”指针。 如果p是指向T的指针,指向类型为T的有效对象,则计算p + 1始终有效,即使*p可能是单个对象,也可能是数组末尾的对象。 在这种情况下,您会得到一个“过去结束”指针,该指针不指向有效对象,但仍然是有效指针。 您可以将此指针用于指针算术,甚至取消引用它以产生左值,只要您不尝试读取或写入该左值即可。 请注意,您只能在对象的末尾前进一个字节; 试图进一步导致未定义的行为。

表达式&numbers为您提供数组的地址,而不是第一个成员(尽管在数字上它们是相同的)。 该表达式的类型是int (*)[7] ,即指向大小为7的数组的指针。

表达式&numbers + 1sizeof(int[7])字节添加到array的地址。 结果指针指向数组后面。

然而问题是当你用*(&numbers + 1)取消引用这个指针时。 取消引用指向一个元素超过数组末尾的指针会调用未定义的行为 。

获取数组元素数量的正确方法是sizeof(numbers)/sizeof(numbers[0]) 。 这假定数组是在当前范围内定义的,而不是函数的参数。

但是我的理解和数组给出了数组第一个元素的地址。

这种理解具有误导性。 &array给出&array的地址。 当然,该地址的值与第一个元素的值相同,但表达式的类型不同。 表达式&array的类型是“指向类型为T的N个元素的数组的指针”(其中N是您要查找的长度,T是int )。

但不应该*(&array + 1)给出该地址的值。

是的……但是在这里表达的类型变得很重要。 指向数组的指针(而不是指向数组元素的指针)将导致数组本身。

在减法表达式中,两个数组操作数都衰减为指向第一个元素的指针。 由于减法使用衰减指针,因此指针算术的单位是元素大小。

我认为这是计算数组长度的简便方法

有更简单的方法:

 std::size(numbers) 

而在C:

 sizeof(numbers)/sizeof(numbers[0])