为什么我能够使用数组索引访问其他变量?

时间:2010-07-22 18:44:11

标签: c

此处 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

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(或者你实际例子中的任何东西)。但是,你可以超越数组的界限,这绝对不是一个肯定的事实,所以你不能依赖它。即使未被发现,它也是“索引超出范围的错误”,也是错误的来源。