以下代码是否在数组[10] = 22或数组[9999] = 22? 我只想弄清楚整个代码是否会在它出错之前执行。 (用C语言编写)。
#include <stdio.h>
int main(){
int array[10];
int i;
for(i=0; i<9999; ++i){
array[i] = 22;
}
return 0;
}
答案 0 :(得分:13)
这取决于...... 如果数组[9]之后的内存是干净的,那么可能不会发生任何事情,直到有一段内存到达被占用的内存段。
试用代码并添加:
printf("%d\n",i);
循环中的,你会看到它崩溃和烧伤的时间。 我得到了各种结果,范围从596到2380.
答案 1 :(得分:9)
使用debugger?
$ gcc -g seg.c -o so_segfault
$ gdb so_segfault
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) run
Starting program: /.../so_segfault
Program received signal SIGSEGV, Segmentation fault.
0x080483b1 in main () at seg.c:7
7 array[i] = 22;
(gdb) print i
$1 = 2406
(gdb)
实际上,如果再次运行它,您将看到对于相同的i值,并不总是会发生段错误。可以肯定的是,它发生在i&gt; = 10时,但是没有办法确定它将崩溃的i的值,因为这不是确定性的:它取决于内存的分配方式。如果内存是空闲的,直到数组[222](也就是没有其他程序使用它),它将一直持续到i = 222,但它也可能因为i> = 10的任何其他值而崩溃。
答案 2 :(得分:8)
答案可能是。 C语言说 nothing 关于在这种情况下应该发生什么。这是未定义的行为。编译器不需要检测问题,做任何事情来处理问题,终止程序或其他任何东西。所以什么也没做。
你写的不是你的记忆,在实践中可能会发生以下三种情况之一:
写出界限:就是不要这样做。 C语言在发生时不会告诉你什么,所以你必须自己关注它。
答案 3 :(得分:4)
您的代码崩溃的时间和方式不确定。它取决于您运行代码的平台。
array
是一个堆栈变量,因此编译器将为堆栈保留10 * sizeof(int)
个字节。根据编译器如何排列其他局部变量以及堆栈增长的方式,i
可能会在array
之后。如果您遵循Daniel的建议并将printf
声明放入,您可能会注意到一个有趣的效果。在我的平台上,当i = 10
,array[10] = 22
clobbers i
和下一个分配到array[23]
时。
当用户代码尝试触摸无权访问的页面时,会发生分段违规。在这种情况下,如果您的堆栈足够小以至于9999次迭代从堆栈中耗尽,您将得到一个。
如果您已经在堆上分配了array
(使用malloc()
),那么当您运行页边界的末尾时,您将获得一个SIGSEGV。即使是10字节的分配也会返回整页。页面大小因平台而异。请注意,某些malloc调试器可以尝试标记数组越界的情况,但除非在您运行页面末尾时涉及硬件,否则您将无法获得SIGSEGV。
答案 4 :(得分:3)
你的代码段错误取决于你正在使用的编译器,运气和相关程序的其他链接细节。对于i == 10
,您很可能不段错误。即使它在您的阵列之外,您几乎肯定会在该位置为您的进程分配内存。但是,当您继续超出数组范围时,最终会将内存分配给您的进程,然后进行段错误。
但是,如果超出数组边界,则可能会覆盖同一堆栈帧中的其他自动变量。如果这些变量中的任何一个是指针(或稍后使用的数组索引),那么当您引用这些现在已损坏的值时,您可能会采用段错误。 (取决于损坏的确切值以及您现在是否要引用未分配给您的进程的内存。)
这不是非常确定的。
答案 5 :(得分:2)
分段错误, 这不容易预测。当i == 10时,它在数组之外......但可能仍然在进程的内存中。这取决于如何分配进程内存,无法(通常)知道(取决于操作系统的内存管理器)。因此,段错误可能发生在i = 10 - 9999中的任何一个,或者根本不发生。
答案 6 :(得分:0)
我建议使用GDB调查此类问题:http://www.gnu.org/software/gdb/documentation/
答案 7 :(得分:0)
更一般地说,您可以使用调试器找出Linux系统中发生分段故障的位置。例如,要使用gdb,请使用-g标志编译带有调试符号的程序,例如:
gcc -g segfault.c -o segfault
然后,使用--args标志,.g。:
使用您的程序和任何参数调用gdbgdb --args ./segault myarg1 myarg2 ...
然后,当调试器启动时,键入run
,程序应运行直到收到SIGSEGV,并且应该在收到该信号时告诉您它在源代码中的位置。