为什么我可以在C ++中访问大于数组大小的数组索引?

时间:2013-11-02 19:56:51

标签: c++ arrays

我正在编写代码并意识到我可以“访问”与数组大小相同或更大索引的数组元素。为什么这不会产生错误?

例如,

#include <iostream>
using namespace std;

int main ()
{
    int b_array[5] = {1, 2, 3, 4, 5};


    cout << b_array[5]  << endl  // Returns 0
         << b_array[66] << endl; // Returns some apparently random value.

    return 0;
}

4 个答案:

答案 0 :(得分:6)

唯一的技术答案是“因为C ++语言规范说的”。访问越界值是未定义的行为。你的个人品味无关紧要。

在“未定义的行为”背后(C ++规范中有很多),需要让编译器开发人员根据他们必须运行的平台实现不同的优化。

如果你认为索引经常在循环中使用,如果你检查边界,你最终会检查每次迭代,总是成功(因此浪费处理器时间)。

答案 1 :(得分:4)

由于产生的性能损失,C ++没有实现边界检查 例如,vector模板包含at()函数,该函数检查边界,但比[]运算符慢〜5倍。 低级语言倾向于迫使程序员生成安全且无错误的代码以换取高性能。

答案 2 :(得分:3)

尽管有一些简单的情况,例如编译器和/或静态分析器可以检测到访问超出范围的情况,但在编译时通常不能这样做。例如,如果将数组传递给函数,它会立即衰减为指针,编译器无法在编译时进行边界检查。

替代的运行时边界检查比较昂贵:对每次访问进行检查会将简单的内存取消引用变为可能停滞的分支。为了使事情变得更加困难,你可以在指针上使用dereference运算符,即你甚至不知道在哪里找到实际数组对象的大小。

因此,有意识地进行了越界数组访问的行为 undefined :系统可以跟踪这些访问,但它不会必须。此外,没有指定系统实际对越界数组访问所做的事情,即,它可以根据上下文做不同的事情。在许多情况下,它只会返回垃圾,这实际上并不太有用。但是,特别是在适当的调试设置下,系统可能会在检测到违规时assert()。{/ p>

答案 3 :(得分:3)

C ++允许直接访问您的程序。没有为您完成边界检查。这可能是非常讨厌的错误的原因,但与其他“更安全”的语言相比,它也非常有效。

数组只是指向内存位置的指针。您尝试访问的索引(例如array [66]中的索引66)通过将66 * sizeof(int)添加到数组的起始地址来解决。最终计算的地址是否在某些范围内是超出了编译器检查的内容。

换句话说,array [i]与C ++中的*(array + i)相同。事实上,您可能会感到惊讶array [i]也可以写成i [array]