问题:
定义一个数组array[5],那么数组包含了array[0],array[1],array[2],array[3],array[4],那array[5],array[6]…会是什么呢? 很多书里面都会说array[5]会出现下标越界的错误,没错这确实是越界了,但实际上编译器并不会给你报错。
下面来看一段代码
#include <stdio.h>
void showArray(int *array, int arrayLenth)
{
for (int i = 0; i < arrayLenth; i++)
{
printf("address:%#x, array[%d]:%d\n", array + i, i, array[i]);
}
printf("\n");
}
int main()
{
int k = -6;
int array[5] = {0, 1, 2, 3, 4};
int j = -520;
printf("address:%#x, j:%d\n", &j, j);
printf("address:%#x, array[%d]:%d\n", array - 1, -1, array[-1]);
showArray(array, 5);
printf("address:%#x, array[%d]:%d\n", array + 5, 5, array[5]);
printf("address:%#x, array[%d]:%d\n", array + 6, 6, array[6]);
printf("address:%#x, array[%d]:%d\n", array + 7, 7, array[7]);
printf("address:%#x, k:%d\n", &k, k);
return 0;
}
使用的是windows gcc编译器
address:0xe37ff9ec, j:-520
address:0xe37ff9ec, array[-1]:-520
address:0xe37ff9f0, array[0]:0
address:0xe37ff9f4, array[1]:1
address:0xe37ff9f8, array[2]:2
address:0xe37ff9fc, array[3]:3
address:0xe37ffa00, array[4]:4
address:0xe37ffa04, array[5]:359
address:0xe37ffa08, array[6]:16
address:0xe37ffa0c, array[7]:-6
address:0xe37ffa0c, k:-6
画出内存分布图
同样的代码使用linux gcc编译器编译
address:0xa8c76a5c, j:-520
address:0xa8c76a5c, array[-1]:-520
address:0xa8c76a60, array[0]:0
address:0xa8c76a64, array[1]:1
address:0xa8c76a68, array[2]:2
address:0xa8c76a6c, array[3]:3
address:0xa8c76a70, array[4]:4
address:0xa8c76a74, array[5]:32764
address:0xa8c76a78, array[6]:348207360
address:0xa8c76a7c, array[7]:901600418
address:0xa8c76a58, k:-6
画出内存分布图
结论
很明显可以看出越界后的array[5],array[6]。。。是取到了什么值,有可能是随机值,也有可能是越界访问到定义array数组上下文的变量。而且不同操作系统的编译器还有差异。 那为什么定义了array[5],array[5]编译器不会报错呢,因为[]这个本质是解引用,什么意思,即array[5] = *(array+5)=*(&(array[5])), 中括号里面的值是基于类型的偏移量,而array则是array[0]的地址,也即数组array[5]的首地址。访问一个地址是一个非常正常的操作,编译器自然不会报错,当然如果你访问了一个不可访问的地址,那编译器确实是会报错误的。 所以数组越界的写法本身没有错,但是注意这样的写法是不规范的,会对他人造成误解,且也没有必要这样写。
|