Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 数组索引越界行为_C++_C_Arrays - Fatal编程技术网

C++ 数组索引越界行为

C++ 数组索引越界行为,c++,c,arrays,C++,C,Arrays,为什么C/C++在数组索引越界的情况下会有所不同 #include <stdio.h> int main() { int a[10]; a[3]=4; a[11]=3;//does not give segmentation fault a[25]=4;//does not give segmentation fault a[20000]=3; //gives segmentation fault return 0; } #包括 in

为什么C/C++在数组索引越界的情况下会有所不同

#include <stdio.h>
int main()
{
    int a[10];
    a[3]=4;
    a[11]=3;//does not give segmentation fault
    a[25]=4;//does not give segmentation fault
    a[20000]=3; //gives segmentation fault
    return 0;
}
#包括
int main()
{
INTA[10];
a[3]=4;
a[11]=3;//不给出分段错误
a[25]=4;//不给出分段错误
a[20000]=3;//给出分段错误
返回0;
}
我知道在
a[11]
a[25]
的情况下,它试图访问分配给进程或线程的内存,而在
a[20000]
的情况下,它超出了堆栈边界


为什么编译器或链接器不给出错误,他们不知道数组的大小吗?如果没有,那么
sizeof(a)
如何正确工作?

问题是C/C++实际上没有对数组执行任何边界检查。这取决于操作系统,以确保您访问的是有效内存

在这种情况下,您将声明一个基于堆栈的数组。根据具体的实现,访问数组边界之外的内容只需访问已分配堆栈空间的另一部分(大多数操作系统和线程为堆栈保留一定的内存部分)。只要您恰好在预先分配的堆栈空间中玩,一切都不会崩溃(注意,我没有说工作)

最后一行发生的情况是,您现在已经访问了分配给堆栈的内存部分之外的内容。因此,您将索引到未分配给进程或以只读方式分配的内存部分。操作系统看到这一点并向进程发送seg故障


这就是C/C++在边界检查方面如此危险的原因之一。

通常只有在尝试访问进程不拥有的内存时,才会出现分段错误

a[11]
(顺便说一句,
a[10]
)的情况下,您看到的是您的进程确实拥有但不属于
a[]
数组的内存
a[25000]
远远不是
a[]
,它可能完全超出了你的记忆范围


更改
a[11]
更加隐蔽,因为它会悄悄地影响不同的变量(或堆栈帧,当函数返回时可能会导致不同的分段错误)。

C没有这样做。操作系统的虚拟内存子系统是

如果您只是稍微超出了范围,那么您正在寻址为您的程序分配的memeory(在本例中是在堆栈调用堆栈上)。在你远远超出范围的情况下,你寻址的内存没有交给你的程序,操作系统抛出了一个分段错误


在某些系统上,还存在操作系统强制执行的“可写”内存概念,您可能试图写入您拥有但标记为不可写的内存。

这不是C问题,而是操作系统问题。您的程序已被授予一定的内存空间,您在其中执行的任何操作都可以。只有在访问进程空间之外的内存时,才会发生分段错误


并非所有操作系统的每个进程都有单独的地址空间,在这种情况下,您可以在没有警告的情况下损坏另一个进程或操作系统的状态

segfault不是C程序的预期操作,它会告诉您索引超出范围。相反,这是未定义行为的意外结果

在C++和C++中,如果声明一个数组,比如

type name[size];
您只能访问索引从
0
size-1
的元素。超出该范围的任何内容都会导致未定义的行为。如果索引接近该范围,则很可能您读取了自己程序的内存。如果索引在很大程度上超出范围,则很可能您的程序将被操作系统终止。但你不知道,任何事情都有可能发生

为什么C允许这样做?C和C++的基本要点是如果性能不好,就不能提供特征。C和C++已经被用于高性能关键系统的AGEs。C已被用作内核和程序的实现语言,在这些内核和程序中,数组边界外的访问对于快速访问内存中相邻的对象非常有用。让编译器禁止这样做是徒劳的

为什么它不发出警告呢?好吧,你可以把警告级别设置得很高,并希望编译器能宽恕你。这称为实施质量(QoI)。如果某些编译器使用开放行为(如未定义的行为)来做一些好事,那么它在这方面的实现质量很好

[js@HOST2 cpp]$ gcc -Wall -O2 main.c
main.c: In function 'main':
main.c:3: warning: array subscript is above array bounds
[js@HOST2 cpp]$

相反,如果它在看到阵列被越界访问时格式化硬盘(这对它来说是合法的),那么实现的质量将相当差。我很喜欢阅读文档中的这些内容。

补充一下其他人的说法,在这种情况下,你不能仅仅依靠程序崩溃,如果你试图访问超出“数组边界”的内存位置,将无法保证会发生什么。这与你做了类似的事情一样:

int *p;
p = 135;

*p = 14;

这只是随机的;这可能有用。可能不会。不要这样做。代码来防止这类问题。

正如litb提到的,一些编译器可以在编译时检测到一些越界的数组访问。但编译时的边界检查并不能捕获所有内容:

int a[10];
int i = some_complicated_function();
printf("%d\n", a[i]);

要检测到这一点,必须使用运行时检查,而在C语言中由于它们的性能影响而避免使用这些检查。即使知道a在编译时的数组大小,即(a),如果不插入运行时检查,它也无法防止这种情况。

正如我理解的问题和注释一样,您理解为什么在访问内存超出范围时会发生不好的事情,但您想知道为什么您的特定编译器没有警告您

允许编译器向您发出警告,许多编译器会在最高警告级别发出警告。然而,编写该标准是为了允许人们为各种开发工具运行编译器