(我在 VirtualBox Ubuntu 上运行它)所以我的问题是:为什么可以在 8 字节数组中输入 11 个字符?
11+1 表示零终止 = 12 个字符。当gets() 将13 个字符写入arr[8] 时发生IOW 崩溃。
您尚未发布精确的堆栈跟踪,但根据我的经验,它应该在 foo() 返回后崩溃。
堆栈帧(带有 for void foo() + gets())看起来像 (*):
- <低内存地址>
- 获取()局部变量
- 在 gets() 调用时保存的堆栈指针(所谓的“序言”)
- 返回地址,指向 foo()
- foo() 局部变量(你的 char arr[8])
- 在 gets() 调用时保存的堆栈指针
- 返回地址,指向 foo() 的调用者
- <更高的内存地址>
从所有信息中,最重要的位是返回地址和保存的堆栈指针。在您的情况下,写入第 13 个字节可能已经损坏了 foo() 函数的已保存堆栈指针。很可能调用以下 printf() 会成功,因为堆栈指针仍然有效(最后通过从 gets() 返回更改)。但是从 foo() 返回会导致 foo() 保存的堆栈指针(现在已损坏)被恢复,然后从调用函数内部访问堆栈的任何操作都会转到错误的地址。
根据我的经验,这是最可能的情况。当堆栈损坏时,很难确定会发生什么。
(*) 有关如何构建堆栈帧的详细信息,请查找 ABI - 应用程序二进制接口 - 适用于您的架构:例如 Intel i386 的 IA-32 ABI 或 AMD64 的 AMD64 ABI。