C / C ++程序是否可以从数组的末尾读取(UNIX)?

我知道,你可以阅读过去的数组结尾 – 我想知道现在是否可以通过执行该阅读操作seg-fault虽然。

int someints[100]; std::cerr << someints[100] << std::endl; //This is 1 past the end of the array. 

第二行是否会导致seg-fault或只是打印乱码? 另外,如果我改变了内存,那么是否会导致在特定行中发生seg-fault,或者只有当别的事情试图使用那个意外更改的内存时才会发生故障?

这是未定义的行为,完全取决于操作系统为进程安排的虚拟内存布局。 一般来说你可以:

  • 访问属于你的虚拟地址空间,但有一个毫无意义的价值,或者一些胡言乱语
  • 尝试访问受限制的内存地址,在这种情况下,内存映射硬件会调用页面错误,操作系统将决定是否使用进程或分配更多内存。

如果someints是堆栈中的一个数组,并且是声明的最后一个变量,那么您最有可能在堆栈顶部获得一些乱码,或者(非常不可能)调用页面错误,从而使操作系统调整堆栈大小或者终止进程与一个SIGSEGV

想象一下你在你的数组之后声明一个int

 int someints[100]; int on_top_of_stack = 42; std::cerr << someints[100] << std::endl; 

那么很可能程序应该打印42 ,除非编译器以某种方式重新排列堆栈上的声明顺序。

是的,如果程序不能访问那个地址的内存,它可以是段错误。 在你的情况下,它不太可能作为数组分配在堆栈上,只有100个字节长,堆栈大小明显更大(即在Linux 2.4.X每个线程8 MB),所以会有未初始化的数据。 但在某些情况下,它可能会崩溃。 在这两种情况下,这个代码都是错误的,像Valgrind这样的分析器应该可以帮助你排除故障。

第二行可以引起任何事情的发生,并且就语言规范而言仍然是正确的。 它可以打印乱码,由于分割错误或其他原因可能会崩溃,可能会导致整个东部海岸外的电源,或者可能导致规范的恶魔飞出你的鼻子 。

这是未定义行为的魔力。