一旦为索引 1 赋值,就会出现预期的分段错误吗?
在代码片段中,我预计在尝试为 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[0] -> int 计数[1]
, 也避免激烈的战争。
In the code snippet, I expected a segmentation fault as soon as trying to assign a value to count[1]
. However the code continues and executes the second for-loop, only indicating a segmentation fault when the program terminates.
#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;
}
Could someone explain what is happening?
Reasons for edit:
Improved the example code as per comments of users,int count[0] -> int count[1]
,
too avoid flame wars.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
你写的内容超出了数组的范围。这并不意味着您会遇到分段错误。这只是意味着您有未定义的行为。您的程序的行为不再受 C 标准的限制。任何事情都可能发生(包括看起来有效的程序)——段错误只是一种可能的结果。
实际上,当您尝试访问操作系统未映射到进程的内存页时,就会发生分段错误。在典型的 x86 PC 上,每个页面都是 4KB,因此基本上,您的进程可以访问 4KB 块中的内存,并且如果您在当前块之外写入,则只会出现段错误。
使用您使用的小索引,您仍然停留在分配给您的进程的当前内存页面内,因此 CPU 不会检测到您正在越界访问内存。
You're writing beyond the bounds of the array. That doesn't mean you're going to get a segmentation fault. It just means that you have undefined behavior. Your program's behavior is no longer constrained by the C standard. Anything could happen (including the program seeming to work) -- a segfault is just one possible outcome.
In practice, a segmentation fault occurs when you try to access a memory page that is not mapped to your process by the OS. Each page is 4KB on a typical x86 PC, so basically, your process is given access to memory in 4KB chunks, and you only get a segfault if you write outside the current chunk.
With the small indices you're using, you're still staying within the current memory page, which is allocated to your process, and so the CPU doesn't detect that you're accessing memory out of bounds.
当您写入超出数组范围时,您可能仍在进程控制下将数据写入内存区域;您几乎肯定还会覆盖其他软件使用的内存,例如堆或堆栈帧管理代码。只有当该代码执行时,例如当当前函数尝试返回时,您的代码才可能出错。事实上,你真的希望出现段错误。
When you write beyond the array bounds, you are probably still writing data into the area of memory under the control of your process; you are also almost certainly overwriting memory used by other software, such as heap or stack frame management code. It is only when that code executes, such as when the current function attempts to return, that your code might go awry. Actually, you really hope for a seg fault.
您的代码已损坏:
始终以高警告级别进行编译,例如 GCC 的
-Wall -pedantic
。编辑:
您实际上所做的是破坏
main
的函数堆栈帧。由于现在堆栈几乎总是向下增长,所以发生了这样的情况:main
参数的堆栈内存并将地址返回到crt0
例程。main
返回时,由于返回地址已被 fubar-ed,因此会触发分段错误。这是缓冲区溢出的典型案例,也是许多网络蠕虫的基础。
在调试器下运行程序并检查局部变量的地址。在 GDB 中,您可以说
set backtrace past-main
,这样 backtrace 就会向您显示通向main
的所有例程。顺便说一句,无需零长度数组也可以实现相同的效果 - 只需使其大小小于循环迭代的次数即可。
Your code is broken:
Always compile with high warning levels, for example
-Wall -pedantic
for GCC.Edit:
What you are effectively doing is corrupting
main
s function stack frame. Since stack nowadays pretty much always grows down, this is what's happening:main
parameters and return address tocrt0
routines.main
returns the segmentation fault is triggered since return address is fubar-ed.This is a classic case of buffer overrun and is the basis of many network worms.
Run the program under the debugger and check the addresses of local variables. In GDB you can say
set backtrace past-main
so backtrace would show you all the routines leading tomain
.By the way, the same effect could be achieved without zero-length array - just make its size smaller then number of loop iterations.