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

时间:2018-10-09 17:22:58

标签: c++ c arrays pointers pointer-arithmetic

我想知道*(&array + 1)的实际工作方式。我认为这是一种计算数组长度的简单方法,希望在使用前正确理解它。我对指针算术不是很有经验,但是根据我的理解&array给出了数组第一个元素的地址。 (&array + 1)就地址而言将转到数组的末尾。但不应该*(&array + 1)给出该地址处的值。而是打印出地址。非常感谢您的帮助,使我的脑海中的指针变得清晰起来。

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

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

3 个答案:

答案 0 :(得分:6)

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

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

但是,问题是当您随后用*(&numbers + 1)取消引用此指针时。取消引用指向数组末尾一个元素的指针将调用undefined behavior

获取数组元素数的正确方法是sizeof(numbers)/sizeof(numbers[0])。假定该数组是在当前作用域中定义的,而不是函数的参数。

答案 1 :(得分:4)

(此答案适用于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也总是有效的。单个对象或数组末尾的对象。在这种情况下,您将获得“过去”指针,该指针不指向有效对象,但仍然是有效指针。您可以将此指针用于指针算术,甚至取消引用它以产生一个左值,只要您不尝试通过该左值读取或写入即可。注意,您只能在对象的末尾再过一个字节。尝试任何进一步的行为都会导致不确定的行为。

答案 2 :(得分:2)

  

但据我了解,&array给出了数组第一个元素的地址。

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

  

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

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

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

  

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

有更简单的方法:

std::size(numbers)

在C中:

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