在代码段中,我想在尝试为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]
,
也避免火焰战争。
答案 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
的所有例程。
顺便说一下,在没有零长度数组的情况下可以实现相同的效果 - 只需使其大小小于循环迭代次数。