此处 len 位于A [10]且 i 位于A [11]。有没有办法捕捉这些错误? 我尝试使用gcc -Wall -W进行编译,但没有显示任何警告。
int main()
{
int A[10];
int i, len;
len = sizeof(A) / sizeof(0[A]);
printf("Len = %d\n",len);
for(i = 0; i < len; ++i){
A[i] = i*19%7;
}
A[i] = 5;
A[i + 1] = 6;
printf("Len = %d i = %d\n",len,i);
return 0;
}
输出 Len = 10 Len = 5 i = 6
答案 0 :(得分:7)
您正在访问数组范围之外的内存;在C中,没有对数组索引进行边界检查。
在技术上访问超出数组末尾的内存会导致未定义的行为。这意味着无法保证您执行此操作时会发生什么。在您的示例中,您最终会覆盖另一个变量占用的内存。但是,未定义的行为也可能导致应用程序崩溃或更糟。
有没有办法来捕捉这些错误?
编译器可以捕获这样的错误,但不是很多。通常不可能在编译时捕获这种错误并报告警告。
静态分析工具可以捕获此类错误的其他实例,通常用于报告有关可能导致此类错误的代码的警告。
答案 1 :(得分:2)
C通常不进行边界检查,但是很多人已经实现了对C的边界检查。例如,在http://sourceforge.net/projects/boundschecking/有一个GCC补丁。当然,边界检查确实有一些开销,但它通常可以在每个文件的基础上启用和禁用。
答案 2 :(得分:1)
A的数组分配在内存中与i和len相邻。请记住,当你通过一个数组进行寻址时,它就像使用指针一样,并且你走出阵列的末端,碰到你放在那里的其他东西。
默认情况下,C不进行边界检查。作为一名程序员,你应该小心谨慎;作为交换,你可以获得速度和尺寸优势。
通常外部工具(如lint)将通过静态代码分析来捕获问题。某些库(取决于编译器供应商)将添加额外的填充或内存保护,以检测您何时走出结束。
许多有趣,危险和不便携的东西都存在于“随机点”的记忆中。堆内存分配的大部分内容都发生在编译器提供给你的内存位置之前。
一般规则是,如果您没有分配或请求它,请不要乱用它。
答案 3 :(得分:0)
我在内存中的位置刚好超过了A的结尾。每个编译器和每个架构都无法保证这一点,但很可能没有理由以任何其他方式执行此操作。
请注意,从0到9计数,您有10个元素。
答案 4 :(得分:0)
数组索引从0开始。因此,数组的大小等于比声明的值小1。你正在覆盖超出允许范围的内存。
这些错误可能不会被报告为警告,但您可以使用诸如“预防”,“麻雀”,“Klockworks”或“净化”等工具来查找此类“不当行为”,如果我可以将其称为“错误行为”。
答案 5 :(得分:0)
简短的回答是局部变量位于堆栈上,索引就像*(ptr + index)。因此,可能会发生int [N]的房间与另一个int x的房间相邻;例如x位于最后一个y之后。所以,y [N-1]是最后一个y,而y [N]是过去y之后的int,在这种情况下,偶然地,你会得到x(或者你实际例子中的任何东西)。但是,你可以超越数组的界限,这绝对不是一个肯定的事实,所以你不能依赖它。即使未被发现,它也是“索引超出范围的错误”,也是错误的来源。