内存越界与相邻内存覆盖问题

先上一段代码:

int i;

int a[10];

for(i=0; i<=10; i++)

{

  a[i] = 0;

}

 

根据ANSI C标准规定:数组中实际不存在的“溢界”元素的地址位于数组所占内存之后,可以对这个地址赋值和比较,但是不能引用该元素。

 

在我的机器上,得到:

&i         = 0x22ff4c

&a[10] = 0x22ff38

&a[15] = 0x22ff4c

 

  可以看出,在这机器上,编译器按照内存地址递减的方式来给变量分配内存,变量i在数组a之后,按以上结果来看,编译器给数组多分配5个元素的内存,但是,如果在某些机器上,编译器严格按需分配,那么对a[10]操作就是对变量i操作,这并不是我们所需要的。此时,本来循环计数器i的值为10,循环体内将不存在的a[10]设置为0,实际上却是将计数器i的值设置为0,这就陷入了一个死循环。如下图所示:

 

再看一例:

main()

{

  int i;

  char c;

  for(i=0; i<5; i++)

  {

         scanf(“%d”, &c);

    printf(“%d”, i);

  }

  printf(“ ”);

}

 

这个程序从标准设备读入5个数,在标准输出设备上写5个数,在我的机器上,效果如下:

0 1 2 3 4

0 0 0 0 0 0 1 2 3 4

0 0 0 0 0 0 1 2 3 4

0 0 0 0 0

黄色的是输入,将这样一直循环下去。为什么呢?这里c被声明为char类型,而不是int类型。然而scanf函数并不能分辨接受的是int*(指针)还是char*(指针),只是将这个指针当成是指向整数的指针来接受,并把指针指向的位置存储一个整数。但是,整数所占的存储空间要大于字符所占的存储空间,所以字符c附近的内存将被覆盖。

如果编译器按照内存地址递减的方式来给变量分配内存,整数变量i在字符变量c之后,因此每次读入一个数值到c时,i的低位部分被覆盖为0,i的高位部分本来为0,所以变量i为0,相当于每次i都被重设为0,一直循环。如下图所示:

 

在我的机器上,得到:

&c = 0x22ff53

&i  = 0x22ff54

 

总结一下:

  两个例子的原理一样,都是由于内存的“溢出”对相邻内存的覆盖,只是他们的表现的形式不同。它们有一个相似之处,能通编译器,却对程序造成致命伤害,都是难于发现的bug。

 

原文地址:https://www.cnblogs.com/guanguangreat/p/6140515.html