数组大于分配?

我有一个声明为char buff的数组[8]。 这应该只有8个字节,但看起来像汇编和测试代码,当我输入大于32个字符的东西时,我得到一个分段错误,而我希望它大于8个字符。 为什么是这样?

你说的不是矛盾:

  • 你有8个字符的空间。

  • 输入超过32个字符时出错。

所以呢?

关键是没有人告诉你如果你输入超过8个字符就会得到错误。 这只是未定义的行为 ,任何事情都可以(而且会发生)。

你绝对不能认为没有明显的不当行为certificate你的代码是正确的。 代码正确性只能通过根据语言规则检查代码来validation(尽管一些自动化工具,如valgrind是一个巨大的帮助)。

超出数组末尾的写入是未定义的行为。 未定义的行为意味着没有任何 保证 (包括分段错误)。

换句话说,它可能会做任何事情。 更实际的是,写入可能没有触及任何受保护的内容,因此从操作系统的角度来看,一切都还可以,直到32。

这提出了一个有趣的观点。 对于操作系统来说,从C的角度来看,“完全错误”可能是好的。 操作系统只关心您访问的页面:

  • 是否为您的流程映射了地址?
  • 您的流程是否拥有权利?

如果出现任何问题,你不应该指望操作系统打你。 如果您使用的是Unix,那么这个(slapping)的有用工具就是valgrind。 它会警告你,如果你的过程正在做令人讨厌的事情,即使这些讨厌的东西在操作系统上技术上是可行的。

C数组没有绑定检查。

正如其他人所说,你正在达到未定义的行为; 直到你留在数组的范围内,一切正常。 如果你作弊,就标准而言,任何事情都可能发生,包括你的程序似乎正常工作以及太阳的爆炸。

在实践中发生的事情是,使用堆栈分配的变量,您可能会覆盖堆栈上的其他变量,获得“不可能”的错误,或者,如果您点击编译器输入的金丝雀值,它可能会检测到返回时的缓冲区溢出function。 对于在所谓的堆中分配的变量,堆分配器可能给出了比请求多的空间,因此可能不太容易发现错误,尽管您可能很容易弄乱堆的内部结构。

在这两种情况下,您还可以访问受保护的内存页面,这将导致您的程序被强制终止(对于堆栈,这种情况发生的次数较少,因为通常您必须覆盖整个堆栈才能访问受保护的页面)。

您的声明char buff[8]听起来像是一个堆栈分配变量,尽管如果它是结构的一部分,它可能是堆分配的。 访问数组的超出范围是未定义的行为,称为缓冲区溢出。 堆栈分配的内存上的缓冲区溢出可能会破坏当前堆栈帧以及可能的调用堆栈中的其他堆栈帧。 对于未定义的行为,任何事情都可能发生,包括没有明显错误。 您不会立即期望seg故障,因为堆栈通常是在线程启动时。

对于堆分配的内存,内存管理器通常会分配大块内存,然后从那些较大的块进行子分配。 这就是为什么当你访问超出内存块结束时经常没有出现seg错误的原因。

在内存块的末尾之外访问是未定义的行为。 并且根据标准,对于这样的越界访问导致seg错误或者实际上是明显成功的读或写是完全有效的。 我说显然是成功的,因为如果你正在写作,那么你很可能通过写出界限来产生堆损坏。

除非你没有告诉我们什么,否则你回答了你的问题。

声明

 char buff[8] ; 

意味着编译器抓取8个字节的内存。 如果你尝试将32个字符填入其中,你应该得到一个seg错误,这称为缓冲区溢出。

每个字符都是一个字节(除非你正在使用unicode,它是一个单词)所以你试图将4倍的字符数放入缓冲区。

这是你第一次用C编码吗?