数组大于分配?

时间:2011-11-08 21:54:51

标签: c

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

5 个答案:

答案 0 :(得分:10)

你所说的不是矛盾:

  • 您可以容纳8个字符。

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

那又怎样?

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

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

答案 1 :(得分:6)

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

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

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

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

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

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:2)

C数组没有绑定检查。

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

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

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

答案 4 :(得分:-1)

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

声明

char buff[8] ;

表示编译器会占用8个字节的内存。如果你尝试将32 char 填入其中,你应该得到一个seg错误,称为缓冲区溢出。

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

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