预期分段错误,只要为索引1分配值?

时间:2010-06-19 17:55:05

标签: c arrays memory memory-management segmentation-fault

在代码段中,我想在尝试为count[1]分配值时出现分段错误。然而,代码继续并执行第二个for循环,仅在程序终止时指示分段错误。

#include <stdio.h>

int main()
{
        int count[1];
        int i;

        for(i = 0; i < 100; i++)
        {
                count[i] = i;
        }
        for(i = 0; i < 100; i++)
        {
                printf("%d\n", count[i]);
        }
        return 0;
}

有人可以解释发生了什么吗?

修改原因: 根据用户的评论改进了示例代码, int count[0] -> int count[1], 也避免火焰战争。

3 个答案:

答案 0 :(得分:15)

你的写作超出了数组的范围。这并不意味着你会遇到分段错误。它只是意味着你有未定义的行为。您的程序的行为不再受C标准的约束。任何事情都可能发生(包括程序似乎有效) - 段错误只是一种可能的结果。

实际上,当您尝试访问操作系统未映射到您的进程的内存页时,会发生分段错误。在典型的x86 PC上,每个页面都是4KB,因此基本上,您的进程可以访问4KB块的内存,如果您在当前块之外写入,则只能获得段错误。

使用您正在使用的小索引,您仍然会保留在当前内存页面中,该页面会分配给您的进程,因此CPU不会检测到您正在访问内存超出范围。

答案 1 :(得分:3)

当你在数组范围之外写字时,你可能仍然在你的过程控制下将数据写入内存区域;您几乎肯定会覆盖其他软件使用的内存,例如堆或堆栈框架管理代码。只有当代码执行时,例如当前函数尝试返回时,代码才会出错。实际上,你真的希望有一个段错误。

答案 2 :(得分:2)

您的代码已损坏:

seg.c:5: warning: ISO C forbids zero-size array ‘count’

始终使用高警告级别进行编译,例如GCC为-Wall -pedantic

编辑:

你实际做的是破坏main的功能stack frame 。由于现在堆栈几乎总是在增长,这就是正在发生的事情:

  • 第一个循环覆盖堆栈内存,保存main个参数,并将地址返回crt0个例程。
  • 第二个循环愉快地读取那个记忆。
  • main返回时,会触发分段错误,因为返回地址为fubar-ed。

这是buffer overrun的典型案例,是许多网络蠕虫的基础。

在调试器下运行程序并检查局部变量的地址。在GDB中,您可以说set backtrace past-main,因此回溯会向您显示导致main的所有例程。

顺便说一下,在没有零长度数组的情况下可以实现相同的效果 - 只需使其大小小于循环迭代次数。