我想知道*(&array + 1)
的实际工作方式。我认为这是一种计算数组长度的简单方法,希望在使用前正确理解它。我对指针算术不是很有经验,但是根据我的理解&array
给出了数组第一个元素的地址。 (&array + 1)
就地址而言将转到数组的末尾。但不应该*(&array + 1)
给出该地址处的值。而是打印出地址。非常感谢您的帮助,使我的脑海中的指针变得清晰起来。
这是我正在研究的简单示例:
int numbers[] = {5,8,9,3,4,6,1};
int length = *(&numbers + 1) - numbers;
答案 0 :(得分:6)
表达式&numbers
为您提供数组的地址,而不是第一个成员(尽管在数字上它们是相同的)。此表达式的类型为int (*)[7]
,即指向大小为7的数组的指针。
表达式&numbers + 1
将sizeof(int[7])
字节添加到array
的地址中。结果指针指向数组之后。
但是,问题是当您随后用*(&numbers + 1)
取消引用此指针时。取消引用指向数组末尾一个元素的指针将调用undefined behavior。
获取数组元素数的正确方法是sizeof(numbers)/sizeof(numbers[0])
。假定该数组是在当前作用域中定义的,而不是函数的参数。
答案 1 :(得分:4)
(此答案适用于C ++。)
&numbers
是指向数组本身的指针。它的类型为int (*)[7]
。&numbers + 1
是指向该数组之后的字节的指针,该数组将位于另外7个int
数组。它仍然具有类型int (*)[7]
。*(&numbers + 1)
取消引用此指针,产生类型为int[7]
的左值,指向数组后的字节。*(&numbers + 1) - numbers
:使用-
运算符会强制两个操作数都进行数组到指针的转换,因此可以减去指针。 *(&numbers + 1)
转换为指向数组后字节的int*
。 numbers
转换为指向数组第一个字节的int*
。它们的区别是两个指针之间的int
数-数组中的int
数。编辑:尽管没有&numbers + 1
所指向的有效对象,但这就是所谓的“过去”指针。如果p
是指向T
的指针,指向类型为T
的有效对象,那么即使p + 1
可能是有效的,计算*p
也总是有效的。单个对象或数组末尾的对象。在这种情况下,您将获得“过去”指针,该指针不指向有效对象,但仍然是有效指针。您可以将此指针用于指针算术,甚至取消引用它以产生一个左值,只要您不尝试通过该左值读取或写入即可。注意,您只能在对象的末尾再过一个字节。尝试任何进一步的行为都会导致不确定的行为。
答案 2 :(得分:2)
但据我了解,&array给出了数组第一个元素的地址。
这种理解具有误导性。 &array
给出数组的地址。当然,该地址的值与第一个元素相同,但是表达式的类型不同。表达式&array
的类型是“指向类型T的N个元素的数组的指针”(其中N是您要查找的长度,T是int
)。
但不应
*(&array + 1)
给出该地址处的值。
是的...但是在这里表达式的类型变得很重要。间接指向数组的指针(而不是指向数组元素的指针)将导致数组本身。
在减法表达式中,两个数组操作数均衰减为指向第一个元素的指针。由于减法使用衰减的指针,因此指针算法的单位是元素大小。
我认为这是一种计算数组长度的简单方法
有更简单的方法:
std::size(numbers)
在C中:
sizeof(numbers)/sizeof(numbers[0])