【内存分配问题】【数组下标越界产生的影响】

引言

昨天晚上写代码的时候发现个事情:代码很简单,定义变量 m m m,中间在循环中运算了一个数组 a a a,后面用到了 w h i l e ( m − − ) while(m--) while(m),然后问题来了,m被改变了…纠结了很久没发现问题,后来了解到是数组下标越界产生的影响(盲点,一般数组还是老老实实开大点吧(ps.后文中数组越界是数组下标越界的简写)
今天早上把这个问题提炼出来,进行一个小小的测试吧,如下:

测试

先声明m后声明a

#include<iostream>
using namespace std;
int main()
{	
	int m=10;
	int a[5];
	//看看m和数组a的内存分配地址 
	cout<<"The position of m is"<<" "<<&m<<endl;
	cout<<"The position of a is"<<" "<<&a<<endl; 
	//数组越界测试 
	for(int i=0;i<13;i++){
		a[i]=i;
		printf("a[%d]=%d,m=%d\n",i,a[i],m);
	} 
    return 0; 
}

运行结果

The position of m is 0x70fe18
The position of a is 0x70fe00
a[0]=0,m=10
a[1]=1,m=10
a[2]=2,m=10
a[3]=3,m=10
a[4]=4,m=10
a[5]=5,m=10
a[6]=6,m=6
a[7]=7,m=6
a[8]=8,m=6
a[9]=9,m=6
a[10]=10,m=6
a[11]=11,m=6
a[12]=12,m=6
a[13]=13,m=6
a[14]=14,m=6

--------------------------------

我们注意到:先声明m后声明a时,a的地址是在m之前的,那么越界到下标5时还尚未产生影响,但是越界到下标更大的时候,直接影响到后面的内存地址中的m变量!m的值自然而然被改变了。

先声明a后声明m

The position of m is0x70fdfc
The position of a is0x70fe00
a[0]=0,m=10
a[1]=1,m=10
a[2]=2,m=10
a[3]=3,m=10
a[4]=4,m=10
a[5]=5,m=10
a[6]=6,m=10
a[7]=7,m=10
a[8]=8,m=10
a[9]=9,m=10
a[10]=10,m=10
a[11]=11,m=10
a[12]=12,m=10
a[13]=13,m=10
a[14]=14,m=10

--------------------------------

我们注意到:先声明a后声明m时,m地址在前,a在后哦。那么我们发现虽然数组确确实实越界了,但是并没有对m产生影响(但我并不是说数组越界无影响 甚至没说值得推崇…

再声明一个变量交叉验证

#include<iostream>
using namespace std;
int main()
{	
	char ch='Z'; 
	int a[5];
	int m=10;	
	//看看m和数组a的内存分配地址 
	cout<<"The position of m is"<<" "<<&m<<endl;
	cout<<"The position of a is"<<" "<<&a<<endl;  
	printf("The position of ch is %p\n",&ch);
	//数组越界测试 
	for(int i=0;i<15;i++){
		a[i]=i;
		printf("a[%d]=%d,m=%d,ch=%c\n",i,a[i],m,ch);
	} 
    return 0; 
}
The position of m is 0x70fdfc
The position of a is 0x70fe00
The position of ch is 000000000070fe1b
a[0]=0,m=10,ch=Z
a[1]=1,m=10,ch=Z
a[2]=2,m=10,ch=Z
a[3]=3,m=10,ch=Z
a[4]=4,m=10,ch=Z
a[5]=5,m=10,ch=Z
a[6]=6,m=10,ch=
a[7]=7,m=10,ch=
a[8]=8,m=10,ch=
a[9]=9,m=10,ch=
a[10]=10,m=10,ch=
a[11]=11,m=10,ch=
a[12]=12,m=10,ch=
a[13]=13,m=10,ch=
a[14]=14,m=10,ch=

--------------------------------

论地址:m在a前,ch在a后,所以呢,ch在过度越界后产生了影响。
再交换声明顺序:

	int m=10;
	int a[5];
	char ch='Z'; 
The position of a is 0x70fe00
The position of ch is 000000000070fdff
a[0]=0,m=10,ch=Z
a[1]=1,m=10,ch=Z
a[2]=2,m=10,ch=Z
a[3]=3,m=10,ch=Z
a[4]=4,m=10,ch=Z
a[5]=5,m=10,ch=Z
a[6]=6,m=6,ch=Z
a[7]=7,m=6,ch=Z
a[8]=8,m=6,ch=Z
a[9]=9,m=6,ch=Z
a[10]=10,m=6,ch=Z
a[11]=11,m=6,ch=Z
a[12]=12,m=6,ch=Z
a[13]=13,m=6,ch=Z
a[14]=14,m=6,ch=Z

--------------------------------

产生影响的也就是m了,理所应当的,如果后声明变量,则地址在先声明的变量之前,那么就不会被改变。

内存空间的分配

当然这是编译器是如何给变量分配内存空间的?这就涉及到了更底层的内存分配问题,我们常用函数体内的变量声明是以栈的结构存储的,在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的。


在这里插入图片描述

附上关于内存分配的参考资料:C语言变量声明内存分配

数组越界的安全问题

数组越界,不是说一定就没有内存空间可以分配用于存储数据了,而是说这段内存空间之后的地址中存储的数据是不可见的,如果越界,你输入的数据就开始在紧接着的内存单元中写,这时你有可能篡改了关键的信息…(这也是为什么被改变的m值是越界时的那个写入数据 i 的值)所以我们常用的防止数组越界的方法还是老老实实把数组开足够大(至少可以存储下我们需要存储的内容)

O J OJ OJ常见反馈: R u n t i m e E r r o r Runtime Error RuntimeError

总结

为什么数组越界会让我们一开始定义的变量值发生改变呢?
因为根据编译器的内存分配规则,存在地址的前后顺序及相邻距离的问题,如果越界后的地址是存储我们的另一个变量的,那么一定会受到影响的。

最后,还是别去随意尝试数组越界,开数组时老老实实地去操作吧!

参考资料
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.zwX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值