0

说真的..我是 80 年代的老黑客,手头有一些空闲时间,我想我会'C'大惊小怪

(我的背景是 Forth,它从头到尾做事,所以我学到了很多关于强制错误的知识)

在这种情况下,我设置了一个小数组,我认为它的大小为 3 个元素( 0,1,2 )

如果我运行编译,我会认为我会遇到越界错误,但不,它编译正常并且运行良好

这个不急,但它对那个小秃头不好,所有的东西都在抓挠。


int main()
{
    char members[3][16];  // 3 elements, each 15 char long plus null

    printf("\n enter something..  ");
    scanf( "%s", members[4]);

    printf("\n and something else..  ");
    scanf( "%s", members[5]);

    printf(" %s  ", members[4]);
    printf(" %s\n", members[5]);

    return 0;
}
4

4 回答 4

5

越界访问数组会调用未定义的行为。这意味着任何事情都可能发生,包括在没有任何明显错误的情况下运行。

于 2012-07-21T09:50:06.327 回答
3

C 不做任何边界检查。(Forth 也没有,所以我不确定期望从何而来。)

数组溢出是未定义的行为:允许但不是必需的崩溃。在这种情况下,字节恰好与放置局部变量的堆栈帧位于同一虚拟内存页面中。如果帧接近页面的末尾,CPU 会识别出错误的地址并抱怨溢出。

如果您输出几千字节或几兆字节,您可能会看到您所期望的内容。

于 2012-07-21T09:51:57.323 回答
0

通常,内存分配在 4 kB 页面中。因此,在最后一个变量之后有一些额外的空间,并且您的缓冲区溢出未被检测到。但是,如果在您的members数组之后还有另一个变量并且您写入members[4],则另一个变量将被损坏。

valgrind 和 dmalloc 等工具通常用于检测缓冲区溢出。它们通过在变量周围分配特殊的保护区域并检查没有人在那里写入来工作。

于 2012-07-21T09:51:30.440 回答
0

您错过了堆栈上的主返回地址,并且可能覆盖了主调用者的一些非关键数据,因此您的程序不会崩溃。此外,在某些平台(例如 powerpc)上,堆栈不用于函数调用,返回地址存储在特殊寄存器中(它在需要时被推入堆栈)。所以这个错误的程序不会崩溃是正常的。

更新:此外,在某些系统堆栈上长大(到更高的地址)。至少在 ARM 堆栈增长是可选择的。

于 2012-07-21T10:08:12.747 回答