@Nawaz 和 @celtschk 是对的。您的代码确实调用了未定义的行为,因此这两种行为都是正确的。不过,您看到这种特殊的未定义行为是有原因的。原因值得理解。
当操作系统在运行时加载程序时,它会为它打开一个虚拟地址空间。 在 64 位系统上,虚拟空间从地址 0 延伸到地址 0xffffffffffffffff。
您的系统自然只有一小部分实际物理内存,它需要填充如此巨大的地址空间。此外,您的系统必须在可能同时运行的几个不同进程之间共享它所拥有的内存——每个进程都有自己的私有虚拟地址空间。
所以这就是系统的作用。它最初为您新加载的程序分配一小块内存——可能是 4 kiB——并将其映射到地址空间的一小段,如 0xffffffffffffff000 到 0xffffffffffffffff。你的程序在这个空间中构建了一堆存储的数据对象。如果堆栈增长超过 4 kiB,系统将分配另一个 4 kiB,从 0xffffffffffffe000 到 0xffffffffffffefff,并且将以对正在运行的程序透明的方式进行分配。
只要程序以一种有序的、规定的方式构建和使用它的堆栈,它就好像它不知道对其堆栈大小的任何限制一样运行。但是,如果程序以无序的方式访问内存,那么结果取决于几个因素,但如果访问的是系统从未分配过程序实际内存的地址,肯定会引发系统异常利用。
现在,这个答案遗漏了很多细节。您可能知道还有第二种内存,即堆或动态内存池。 还有其他因素,包括“磁盘交换”。但是,如果指针i
碰巧指向程序已经出于某种目的使用的内存,则不会引发系统异常。它指向这样的记忆吗?很难说。显然,在您的情况下,它似乎在一个系统上这样做,但在另一个系统上却没有。
顺便说一句,我与@celtschk 在一点上略有不同。现代 CPU 和操作系统是专门为防止系统灾难而构建的,就像他所说的那样。C 和 C++ 标准不保证不会发生此类灾难,但操作系统会保证,除非程序以超级用户权限运行(即使这样,也可能存在部分有效的保护措施)。我认为您不必担心使用普通的用户模式程序无意中擦除磁盘。不过,在嵌入式系统上,这是另一回事,@celtschk 是完全正确的。