arr[-1]在c++中的奇怪行为

strange behavior of arr[-1] in c++

本文关键字:c++ arr      更新时间:2023-10-16
#include<iostream>
using namespace std;
int main(){
int arr[] = {1,2,3};
printf("outside loop trail 1: arr[-1] = %d n", arr[-1]);
for(int i = 0; i<10; i++){
printf("ninside loop trail i = %d, arr[-1] = %d n", i, arr[-1]);
}
}

问题:

为什么循环内部的输出是序列0,1,2(与循环索引i相同(;但每次执行代码时,循环外的输出都会发生变化?谢谢

后的输出

g++ -o explore explore.cpp && ./explore

外环轨迹1:arr[-1]=537839344

内环轨迹i=0,arr[-1]=0

内环轨迹i=1,arr[-1]=1

内环轨迹i=2,arr[-1]=2

跑步/第二次探索:

外环轨迹1:arr[-1]=1214220016

内环轨迹i=0,arr[-1]=0

内环轨迹i=1,arr[-1]=1

内环轨迹i=2,arr[-1]=2

这实际上包含在标准中。例如,C++17 [expr.add] /4状态:

将具有整型的表达式添加到指针或从指针中减去时,结果具有指针操作数的类型。如果表达式P指向具有n元素的阵列对象x的元素x[i],则如果0 <= i + j <= n,则表达式P + JJ + P(其中J具有值j(指向(可能假设的(元素x[i + j];否则,行为是未定义的。

我之所以讨论添加指针和整数,是因为根据C++17 [expr.sub] /1array[index]*(array + index)是等价的(这是下标中的sub,而不是减法(:

表达式E1[E2](根据定义(与*((E1)+(E2))相同。

现在有很多需要接受的内容,但这基本上意味着添加"指向数组元素的指针"answers"索引"的结果,会给您一个所需的指针,以指向数组中的一个元素或刚好超出最后一个(1(

由于之前的指针第一个指针(array[-1](不符合该要求,因此这是未定义的行为。一旦你做到了,所有的赌注都会落空,实现可以自由地做它喜欢的事情。你可以庆幸它在播放derisive_laughter.ogg:-(后没有擦除你的硬盘

请注意,负索引本身没有错,下面的代码为您提供了第二个元素(最后的"指针"仍在数组中(:

int array[100];
int *ptrThird = &(array[2]);
int second = ptrThird[-1];

(1(注意,指针可以指向数组之外,前提是您不尝试取消引用它。不幸的是,array[index]是一个取消引用操作,因此,虽然int array[10]; int *p = &(array[10]);有效,但int x = array[10];无效。

这是一个未定义的行为。

一般来说,这样使用数组索引相当于这样做指针数学:

arr[n] -> *(arr+n)

通过使用负索引,可以在与数组数据关联的内存块开始之前引用内存。如果您使用的索引超出了数组的边界,那么正如其他人所指出的,结果是未定义

expr/1:

后缀表达式后面跟一个方括号中的表达式就是后缀表达式。其中一个表达式应为"T的数组"类型的glvalue或"指向T的指针"类型的prvalue,另一个表达式则应为非范围枚举或整型的prvalue。结果属于"T"类型。类型"T"应为完全定义的对象类型表达式E1[E2](根据定义(与*(((E1(+(E2((相同,只是在数组操作数的情况下,如果该操作数是左值,则结果为左值,否则为x值。在表达E2之前对表达E1进行测序。

expr.add/4:

将具有整型的表达式J添加到指针类型的表达式p中或从中减去时,结果的类型为p。
(4.1(如果p的计算结果为空指针值,而J的计算结果则为0,则结果为零指针值
(4.2(否则,如果P指向具有n个元素的数组对象x的元素x[i],则表达式P+J和J+P(其中J具有值J(在0≤i+J≤n时指向(可能是假设的(元素x[i+J],在0≤i−J≤n的情况下表达式P-J指向(可能假设的(元素x[i-J]。
(4.3(否则,行为未定义