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

Calculate array length via pointer arithmetic

本文关键字:数组 计算 算法 指针      更新时间:2023-10-16

我想知道*(&array + 1)实际上是如何工作的。我认为这是一种计算数组长度的简单方法,并希望在使用之前正确理解它。我对指针算术不是很有经验,但根据我的理解&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是指向数组后面的字节的指针,其中将位于另一个 7ints 的数组。它仍然有类型int (*)[7].
  3. *(&numbers + 1)取消引用此指针,生成一个类型为int[7]的左值,引用数组后面的字节。
  4. *(&numbers + 1) - numbers:使用-运算符强制两个操作数进行数组到指针的转换,因此可以减去指针。*(&numbers + 1)将转换为指向数组后面的字节的int*numbers将转换为指向数组第一个字节的int*。它们的区别在于两个指针之间的ints 数---即数组中的ints 数。

编辑:虽然没有&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的类型是"指向 T 类型的 N 个元素数组的指针"(其中 N 是您要查找的长度,T 是int(。

但是*(&array + 1)不应该给出值,它在这个地址。

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

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

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

有更简单的方法:

std::size(numbers)

在 C 中:

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