如果不使用它,访问数组外的数据是否不正确?

时间:2011-07-04 14:40:33

标签: c++ c arrays undefined-behavior

在我写的算法中,我可以得到以下内容(当然简化)

int a[3] = {1,2,3};
int b = a[3];

当用于填充b的索引溢出时,我从不使用b的值。代码仍然不正确吗?我是否必须进行明确的边界检查?

6 个答案:

答案 0 :(得分:5)

此代码具有未定义的行为,无论您是否使用b。为什么?因为a[3]根据定义等同于*(a+3)。这里引用了标准,证明*(a+3)本身是未定义的,无论该值是存储,使用还是单独保留。

  

当一个表达式有积分时   类型被添加到或从中减去   指针,结果有类型   指针操作数。如果指针   操作数指向一个元素   数组对象,数组很大   够了,结果指向了   元素偏离原始   元素这样的差异   结果和的下标   原始数组元素等于   积分表达。换一种说法,   如果表达式P指向第i个   数组对象的元素,   表达式(P)+ N(等效地,   N +(P))和(P)-N(其中N具有   值n)分别指向   第i + n和第i-n个元素   数组对象,只要它们存在。   而且,如果表达P点   到数组的最后一个元素   对象,表达式(P)+1分   一个超过数组的最后一个元素   对象,如果表达式Q指向   一个超过数组的最后一个元素   对象,表达式(Q)-1指向   数组对象的最后一个元素。   如果指针操作数和   结果指向相同的元素   数组对象,或者是最后一个对象   数组对象的元素,   评估不得产生   溢流;否则,行为是   理解过程科幻奈德。

答案 1 :(得分:3)

仍然不正确,仍然是未定义的行为。边界检查。

int b = *(a + 3); // dereferencing beyond the array bound.

答案 2 :(得分:3)

阅读a[3]已导致未定义的行为。由于未定义的行为永远不会受到本地限制,这可能导致您的硬盘驱动器被格式化,或者您的计算机出现在一个巨大的肉食僵尸身上。

实际上,它通常会起作用。但是很容易构成一个数组末尾标记映射内存区域结束的情况,因此访问一个元素会导致分段错误。对于堆栈上的int数组肯定不是这种情况,大多数堆实现都不是这样,但是你不应该依赖它。

(是否取&a[3]的地址也是未定义的行为is heavily disputed。)

答案 3 :(得分:2)

仍然不正确是的,因为您访问越界内存位置以获取值a[3]并将其存储在变量b中。

你从不使用b的事实可能意味着编译器优化了那行代码,所以你可能从来没有看到那条线存在任何不利影响。

但是,编译器不需要这样做,并且代码本身仍然具有未定义的行为。

答案 4 :(得分:1)

使用该值,将其复制到b

更具体地说,不允许解除引用(a+3),因为表达式(a+3)不是有效指针...而表达式 a[3]等同于{ {1}}(其中*(a+3)已经衰减为指针表达式。)

答案 5 :(得分:0)

是的,阅读不会退出的a[3]是错误的。

使用b也是错误的,但已经太晚了。