当我访问数组的超出边界元素时,为什么不会出现运行时错误?

时间:2013-02-01 05:32:19

标签: c++ c arrays runtime-error indexoutofboundsexception

在下面的代码中,我尝试访问数组的'-1'元素,我没有得到任何运行时错误。

#include <stdio.h>

int A[10] = {0};

int main(){

    A[-1] += 12;

    printf("%d",A[-1]);

    return 0;
}

当我运行代码时,它输出12,这意味着它正在向不存在的A [-1]添加12。直到今天,每当我试图访问越界元素时,我都遇到了运行时错误。我之前从未尝试过一个简单的代码。

有谁可以解释为什么我的代码成功运行?

我在计算机和ideone上运行它,在两种情况下都成功运行。

3 个答案:

答案 0 :(得分:1)

C和C ++没有任何边界检查。它是语言的一部分。它是为了使语言更快地执行。

如果您想要边界检查,请使用另一种语言。 Java也许?

当你的代码执行时,你很幸运。

答案 1 :(得分:1)

在C ++(和C)中,数组不检查范围索引。他们不是上课。

在C ++ 11中,您可以使用std::array<int,10>at()函数:

std::array<int,10> arr;

arr.at(-1) = 100; //it throws std::out_of_range exception

或者您可以使用std::vector<int>at()成员函数。

答案 2 :(得分:1)

你看,当你分配一个像这样的变量时,它会落在堆栈上。 Stack在您调用的每个函数中保存有关局部变量的小包信息,用简单的单词表示。运行时能够检查是否超出了已分配堆栈的范围,但是如果在堆栈中的无效位置写入某些数据则无法检查。堆栈可能如下所示:

[4个字节 - 一些ptr] [4个字节 - A&#39的第一个元素] [4个字节 - A&#39的第二个元素] ...

当您尝试分配给数组的第-1个元素时,实际上是尝试读取数组前面的四个字节(四个字节,因为它是一个int数组)。您覆盖了堆栈中保存的一些数据 - 但这些数据仍处于有效进程的内存中,因此系统没有任何投诉。

尝试在Visual Studio中以发布模式运行此代码:

#include <stdio.h>

int main(int argc, char * argv[])
{
    // NEVER DO IT ON PURPOSE!
    int i = 0;
    int A[5];

    A[-1] = 42;
    printf("%d\n", i);

    getchar();
    return 0;
}

编辑:以回应评论。

我错过了一个事实,即A是全球性的。它不会被保存在堆栈中,而是(通常可能)在二进制模块的.data段中,但其余的解释是:A [-1]仍在进程的内存中,因此赋值不会提高AV。但是,这样的赋值将覆盖某些东西,即在A(可能是指针或二进制模块的其他部分)之前导致未定义的行为。

注意,我的示例可能有效,可能不行,具体取决于编译器(或编译器模式)。例如,在调试模式下,程序返回0 - 我猜,内存管理器在堆栈帧之间插入一些哨兵数据,以捕获缓冲区溢出/欠载等错误。