通过指针算法计算数组长度
我想知道*(&array + 1)
实际上是如何工作的。 我认为这是一种计算数组长度的简单方法,并希望在使用之前正确理解它。 我对指针算法不太熟悉,但是我的理解&array
给出了&array
第一个元素的地址。 (&array + 1)
将根据地址到达数组的末尾。 但不应该*(&array + 1)
给出该地址的值。 而是打印出地址。 我非常感谢你的帮助,让我的脑袋里的指针清晰。
这是我正在研究的简单示例:
int numbers[] = {5,8,9,3,4,6,1}; int length = *(&numbers + 1) - numbers;
(这个答案适用于C ++。)
-
&numbers
是指向数组本身的指针。 它的类型为int (*)[7]
。 -
&numbers + 1
是指向数组后面的字节的指针,其中将定位另一个7int
的数组。 它仍然具有类型int (*)[7]
。 -
*(&numbers + 1)
取消引用此指针,产生一个int[7]
类型的左值,指向数组后面的字节。 -
*(&numbers + 1) - numbers
:使用-
运算符强制两个操作数进行数组到指针的转换,因此可以减去指针。*(&numbers + 1)
转换为指向数组后面的字节的int*
。numbers
转换为指向数组第一个字节的int*
。 它们的区别在于两个指针之间的int
数 – 这是数组中int
的数量。
编辑:虽然&numbers + 1
没有指向有效对象,但这就是所谓的“过去结束”指针。 如果p
是指向T
的指针,指向类型为T
的有效对象,则计算p + 1
始终有效,即使*p
可能是单个对象,也可能是数组末尾的对象。 在这种情况下,您会得到一个“过去结束”指针,该指针不指向有效对象,但仍然是有效指针。 您可以将此指针用于指针算术,甚至取消引用它以产生左值,只要您不尝试读取或写入该左值即可。 请注意,您只能在对象的末尾前进一个字节; 试图进一步导致未定义的行为。
表达式&numbers
为您提供数组的地址,而不是第一个成员(尽管在数字上它们是相同的)。 该表达式的类型是int (*)[7]
,即指向大小为7的数组的指针。
表达式&numbers + 1
将sizeof(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])