初识C语言---野指针

 野指针概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。

 

 一、野指针成因

1、指针未初始化就使用

#include
int main()
{
	int* p;                       
	*p = 10;  
	
	return 0;
}

此段代码中,局部变量p未初始化,也就意味着p为随机值没有方向,*p就会非法访问内存空间,此时p就为野指针。

有效改善方法:    初始化为空指针。如果定义指针的时候实在不知道赋什么值,可以先将其定义为空指针,即int*p=NULL;,NULL是代表空指针的意思,后面如果用到指针的话再让指针指向具有实际意义的地址,然后通过指针的解引用改变其指向的内容。

#include
int main()
{
	int* p=NULL;
	

	int b = 8;
	p = &b;         
	*p = 100;
    printf("%d",*p);
	return 0;
}

2、指针越界访问 

#include
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	int* p = arr;
	for (i = 0; i <= 10; i++)
	{
		*p = i;                   //i=10时越界
	}
	return 0;
}


 初识C语言---野指针_第1张图片

 arr整型数组,有10个元素,初始化元素值为0,arr数组名表示首元素地址传给了指针p,通过对指针解引用改变数组元素值,当i=10时,此时*p访问的内存空间不在数组有效范围内,,此时*p就属于非法访问内存空间,p为野指针

 

3、指针指向空间的释放、

#include
int* test()
{
	int a = 10;
	return &a;          //&a=0x0012ff40
}
int main()
{
	int* p = test();
	return 0;
}

程序开始后首先进入主函数,执行第一步,调用test函数将返回值赋给p,test函数的返回值是局部变量a的地址,假设a的地址为0x0012ff40,由于a只在test函数内有效,出了test函数其内存空间就被释放,也就意味着a的地址编号不存在,短时间内如果再次利用这块地址,它的值还未被改变也就是0x0012ff40还存在,p的值为0x0012ff40,但此时p为野指针,因为p里面所存放的地址是无效的。

二、 野指针的避免

1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性

 

 三、关于内存空间释放的补充

 代码:


#include
int* test()
{
	int a = 10;
	return &a;
}
int main()
{
	int* p = test();
	printf("%d", *p);
	return 0;
}

 运行结果:

初识C语言---野指针_第2张图片 

 分析:

初识C语言---野指针_第3张图片

由于a是test函数内的局部变量,而局部变量只有被调用时才会为其分配内存空间,所以进入主函数但未进入test函数时变量a没有内存空间,如上图所示

初识C语言---野指针_第4张图片

 主函数的第一步首先调用test函数,进入test函数后执行到局部变量的定义时就会为其分配内存空间,如上图所示

 ​​​​​​​初识C语言---野指针_第5张图片

 通过对变量的赋值进而对内存空间赋予编号地址,如上图所示

 

初识C语言---野指针_第6张图片

 test函数将局部变量a(int占4个字节)的地址返回给p,即p=0x005BF850,如上图所示

 

初识C语言---野指针_第7张图片

初识C语言---野指针_第8张图片

  由于test函数运行完后test函数内的局部变量所占的内存空间会被释放,即a的内存空间编号0x005BF850不存在,但那块地址还是在的只不过不属于a了,如果没有其他函数调用这块地址,那块地址的名称暂时可能还是0x005BF850 ,观察图中内存窗口程序执行到p定义那一行时内存并未发生变化因为暂无其他函数使用这块空间,如上图所示

所以进行printf函数时打印p所指向的内容*p时还为10,但此时p为非法访问内存空间,为野指针。但如果在打印之前有其他函数调用了这块地址,这块地址的名称就会发生变化,不再是0x005BF850,打印p所指向的内容*p时不再为10。

初识C语言---野指针_第9张图片

 观察图中内存窗口可以发现,执行完printf("%d", *p);后内存发生了变化

代码:

 

#include
int* test()
{
	int a = 10;
	return &a;
}
int main()
{
	int* p = test();
	printf("Hello\n");
	printf("%d", *p);
	return 0;
}
#include
int* test()
{
	int a = 10;
	return &a;
}
int main()
{
	int* p = test();
	printf("Hello\n");
	printf("Welcome!\n");
	printf("%d", *p);
	return 0;
}


 

 运行结果:

初识C语言---野指针_第10张图片

 初识C语言---野指针_第11张图片

 

 分析: 

由于进行printf函数打印p所指向的内容*p之前,Hello利用了那块儿内存,使得那块儿内存的名字不再是0x005BF850,变成了Hello地址的编号,所以打印p所指向的内容*p时的值不再是10,此时就为随机值了。初识C语言---野指针_第12张图片

 观察图中数据可以发现,程序执行完printf("Hello\n");时内存单元就发生了变化,是因此printf函数调用了内存,使得p的值发生了变化,*p也随着变化。

初识C语言---野指针_第13张图片

再执行完printf("Welcome!\n");时内存单元又发生了变化,是因此printf函数调用了内存使得p的值发生了变化,*p也随着变化。

初识C语言---野指针_第14张图片

 

 执行完printf("%d", *p);时内存单元又发生了变化,是因此printf函数调用了内存使得p的值发生了变化,*p也随着变化。

你可能感兴趣的:(初始C,c语言,蓝桥杯,c++)