通过指针算法计算数组长度
Calculate array length via pointer arithmetic
我想知道 *(&array + 1)
实际上是如何工作的。我认为这是计算数组长度的一种简单方法,并希望在使用它之前正确理解它。我对指针运算不是很有经验,但根据我的理解 &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
是指向数组后面字节的指针,另一个 7 int
数组将位于该字节。它的类型仍然是 int (*)[7]
.
*(&numbers + 1)
取消引用这个指针,产生一个 int[7]
类型的左值,引用数组后面的字节。
*(&numbers + 1) - numbers
:使用-
运算符强制两个操作数进行数组到指针的转换,因此可以减去指针。 *(&numbers + 1)
转换为 int*
指向数组后的字节。 numbers
转换为指向数组第一个字节的 int*
。它们的区别在于两个指针之间int
的个数---也就是数组中int
的个数。
编辑:虽然 &numbers + 1
没有指向有效的对象,这就是所谓的 "past the end" 指针。如果 p
是指向 T
的指针,指向类型 T
的有效对象,那么计算 p + 1
总是有效的,即使 *p
可能是单个对象,或数组末尾的对象。在那种情况下,您会得到一个 "past the end" 指针,它不指向有效对象,但仍然是一个有效指针。您可以将此指针用于指针运算,甚至取消引用它以生成左值,只要您不尝试读取或写入该左值即可。请注意,您只能在对象末尾后移动一个字节;试图走得更远会导致未定义的行为。
表达式 &numbers
为您提供 数组 的地址,而不是第一个成员(尽管在数字上它们是相同的)。此表达式的类型是 int (*)[7]
,即指向大小为 7 的数组的指针。
表达式&numbers + 1
将sizeof(int[7])
个字节添加到array
的地址。结果指针指向数组之后。
然而,问题是当您随后使用 *(&numbers + 1)
取消引用此指针时。取消引用指向一个元素超过数组末尾的指针会调用 undefined behavior.
获取数组元素数量的正确方法是sizeof(numbers)/sizeof(numbers[0])
。这假定数组是在当前范围内定义的,而不是函数的参数。
but with my understanding &array gives the address of the first element of the array.
这种理解具有误导性。 &array
给出数组的地址。当然,该地址的值与第一个元素相同,但表达式的类型不同。表达式 &array
的类型是 "pointer to array of N elements of type T"(其中 N 是您要查找的长度,T 是 int
)。
But shouldn't *(&array + 1)
give the value, which is at this address.
嗯,是的...但是表达式的类型在这里变得很重要。间接指向数组的指针(而不是指向数组元素的指针)将导致数组本身。
在减法表达式中,两个数组操作数都衰减为指向第一个元素的指针。由于减法使用了衰减指针,因此指针运算的单位是元素大小。
I saw this as an easy way to calculate the array length
还有更简单的方法:
std::size(numbers)
在 C 中:
sizeof(numbers)/sizeof(numbers[0])
我想知道 *(&array + 1)
实际上是如何工作的。我认为这是计算数组长度的一种简单方法,并希望在使用它之前正确理解它。我对指针运算不是很有经验,但根据我的理解 &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
没有指向有效的对象,这就是所谓的 "past the end" 指针。如果 p
是指向 T
的指针,指向类型 T
的有效对象,那么计算 p + 1
总是有效的,即使 *p
可能是单个对象,或数组末尾的对象。在那种情况下,您会得到一个 "past the end" 指针,它不指向有效对象,但仍然是一个有效指针。您可以将此指针用于指针运算,甚至取消引用它以生成左值,只要您不尝试读取或写入该左值即可。请注意,您只能在对象末尾后移动一个字节;试图走得更远会导致未定义的行为。
表达式 &numbers
为您提供 数组 的地址,而不是第一个成员(尽管在数字上它们是相同的)。此表达式的类型是 int (*)[7]
,即指向大小为 7 的数组的指针。
表达式&numbers + 1
将sizeof(int[7])
个字节添加到array
的地址。结果指针指向数组之后。
然而,问题是当您随后使用 *(&numbers + 1)
取消引用此指针时。取消引用指向一个元素超过数组末尾的指针会调用 undefined behavior.
获取数组元素数量的正确方法是sizeof(numbers)/sizeof(numbers[0])
。这假定数组是在当前范围内定义的,而不是函数的参数。
but with my understanding &array gives the address of the first element of the array.
这种理解具有误导性。 &array
给出数组的地址。当然,该地址的值与第一个元素相同,但表达式的类型不同。表达式 &array
的类型是 "pointer to array of N elements of type T"(其中 N 是您要查找的长度,T 是 int
)。
But shouldn't
*(&array + 1)
give the value, which is at this address.
嗯,是的...但是表达式的类型在这里变得很重要。间接指向数组的指针(而不是指向数组元素的指针)将导致数组本身。
在减法表达式中,两个数组操作数都衰减为指向第一个元素的指针。由于减法使用了衰减指针,因此指针运算的单位是元素大小。
I saw this as an easy way to calculate the array length
还有更简单的方法:
std::size(numbers)
在 C 中:
sizeof(numbers)/sizeof(numbers[0])