segfault with array

关于数组我有两个问题:

第一个是关于以下代码:

int a[30]; //1 a[40]=1; //2 

为什么不是第2行给出segfault,它应该给出因为数组只分配了30个int空间,并且在其分配的空间之外的任何解除引用应该给出段错误。

第二:假设上面的代码有效,那么[40]有可能越过写,因为它没有来自arrray的保留范围。

提前致谢。

这是未定义的行为 – 它可能会崩溃,它可能会无声地破坏数据,它可能不会产生任何可观察到的结果。 不要这样做。

在您的示例中,可能的解释是数组是堆栈分配的,因此数据周围有很多可以写入的地址,因此没有立即可观察到的结果。 但是,根据如何(向更大的地址或更小的地址方向)堆栈在您的系统上增长,这可能会覆盖调用堆栈中的函数的返回地址和临时值,这会使程序崩溃或在尝试时使其行为exception从函数返回。

出于性能原因,C每次访问时都不会检查数组大小。 您还可以通过直接指针访问元素,在这种情况下无法validation访问权限。 只有在超出分配给进程的内存时才会发生SEGFAULT。

对于第二个问题,是的,它可以被覆盖,因为这个内存被分配给你的进程,并且可能被其他变量使用。

它取决于系统分配该arrays的位置,如果由于临时位置40位于操作系统预留存储器中,那么您将收到段错误。

只有当您为系统的其余部分执行非法操作时,您的应用程序才会崩溃:如果您尝试访问程序不拥有的虚拟内存地址,那么您的硬件将注意到的是,将通知您的操作系统,并且它将使用分段错误终止您的应用程序:您访问了一个您不应该访问的内存段。

但是,如果你访问一个随机存储器地址(这就是你所做的:肯定a[40]在你的数组之外,但它可能在哪里),你可以访问一个有效的存储单元(这就是你发生的事情) 。

这是一个错误:您可能会覆盖程序拥有的某些内存区域,从而有可能在其他地方破坏您的程序,但系统无法知道您是出于目的还是错误地访问它并且不会杀死您。

用托管语言编写的程序(即:在受保护的环境中运行的程序检查任何内容)会注意到您的错误内存访问,但C不是托管语言:您可以随心所欲地做任何事情(只要您不这样做)为系统的其余部分创建问题)。

第2行工作并且不引发段错误的原因是因为在C / C ++中,数组是指针。 所以你的数组变量指向一些内存地址,例如1004.数组语法告诉你的程序从a的位置向下找多少字节来查找数组元素。

这意味着

 printf("%p", a); // prints out "1004" 

 printf("%p", a[0]); // prints out "1004" 

应该打印相同的值。

然而,

 printf("%p", a[40]); // prints out "1164" 

从a的地址返回sizeof(int)* 40的内存地址。

是的,它最终会被覆盖。

如果你使用malloc空间,你应该得到一个段错误(或者至少我相信如此),但是当使用数组而不分配空间时,你将能够暂时覆盖内存。 它最终会崩溃,可能是在程序执行数组大小检查时,或者当你打到一个为其他东西保留的内存块时(不知道引擎盖下发生了什么)。

有趣的是,IIRC,efence也不会抓住这个:D。