为什么这段代码表现得很奇怪

Why does this piece of code behave weird?

本文关键字:代码表 为什么      更新时间:2023-10-16

我在C++中有这样的代码,它给出了奇怪的输出:

#include<iostream>
using namespace std;
int main(){
    int r[15]={0};
    int n = 5;
    r[15]=20;
    cout<<n;    
}

输出显然应该是5,但它给了我20。现在我知道r[15]出界了。这段代码应该在尝试访问r[15]时抛出一个异常,不是吗?然而,它使用g++进行正常编译,并给出错误的输出。我不知道是什么导致了这种异常现象。有人能帮忙吗?

仅供参考,这段代码只是一个示例,我必须从一个更大的代码中找出这个错误,这花了我很多时间,否则,如果抛出异常,这些时间本可以保存。

更新:我检查了以下代码:

#include<iostream>
using namespace std;
int main(){
    int n = 5;
    int r[15]={0};
    r[15]=20;
    cout<<n;
}
Output:
20

我也检查了以下代码:

#include<iostream>
using namespace std;
int main(){
    int n = 5;
    int a=5;
    int r[15]={0};
    r[15]=20;
    cout<<n<<endl<<a;
}
Output:
5
5

因此,如果堆栈的解释是正确的,那么在这种情况下,其中任何一个值都应该被修改,对吧?事实并非如此。

由于r是一个15元素的数组,r[14]是最后一个元素。因此r[15]=20;是未定义的行为。C++不进行边界检查,所以在处理纯数组时不会出现异常。

在您的情况下,r[15]=20恰好在存储n的精确位置覆盖堆栈。

现在我知道r[15]是越界的。这段代码应该在尝试访问r[15]时引发异常,不是吗?

除非你使用某种检查库,否则不会。C(和C++)非常接近机器,所以你可以陷入这种情况。(这是它们的一部分功能。)有些编译器上有编译器标志,可以插入边界检查(以运行时为代价),但gcc不这样做(你可以找到补丁集将其作为一种功能添加,尽管我认为只适用于C)。

那里发生的事情(显然)是,您的n变量在r数组的15个插槽之后立即出现在堆栈上:

+-------+|r[0]||r[1]||r[2]|。。。|r[13]||r[14]||n|+-------+

因此,写入越界条目r[15]最终会覆盖它(在您的特定情况下,这不是您可以或应该依赖的行为,堆栈上的事物的顺序并不是由它们在源中声明的顺序决定的,很可能是而不是)。