我希望这会崩溃,但事实并非如此

时间:2012-07-21 09:47:27

标签: c arrays string

严重.. 我是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 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:3)

C不进行任何边界检查。 (Forth也没有,所以我不确定期望来自哪里。)

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

如果你去了几千字节或几兆字节,你可能会看到像你期望的那样。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

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