三、野指针
3.1什么是野指针
野指针:就是指针指向的位置是不可知(随机性,不正确性,没有明确限制的)。
3.2野指针的形成原因
3.2.1、指针未初始化
**指针变量在定义时不会自动初始化,如果未初始化,而是随机的一个值。此时操作指针。指针就是去访问一个不确定的地址,所以结果是不可知的。此时该指针成为野指针。
**解决方案:在定义指针时,要么将其初始化为一个合理的地址,要么初始化为NULL。
#include<stdio.h>
int main()
{//野指针
int* p;//就是野指针
// printf("%d\n",*p); // 未初化,直接用 错误的 因为是随之机值的空间,内存可能被其它占用了。
*p = 10;
--------------------------
int a = 10;
int* p;
p=a; // 也是错误的
//p = &a;
//*p = 100;
printf("%d\n", a);
return 0;
}
3.2.2、指针越界访问
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3 };
int i = 0;
int* p = arr;
for (i = 0; i <= 10; i++)
{
*p = i; //i=10时越界
printf("%d\n", arr[i]);//越界访问会出现一个随机值
}
return 0;
}
//修改
int arr[10] = { 1,2,3,4,5,6,7,8,9 };
int* p1 = arr;
for (int i = 0; i < 10; i++) {
printf("%d\n", *(p1 + i));
printf("%d\n", arr[i]);
}
return 0;
}
3.2.3、指针指向空间的释放后位置为NULL
**在使用free或delete释放内存后,指针指向的内存被销毁,空间被释放,但指针的值并未改变,仍然指向这块内存。
**解决方案:在调用free或delete之后,应立即将该指针置为NULL,以避免成为野指针。
#include<stdio.h>
int* test()
{
int a = 10;
return &a; //&a=0x0012ff40 返回变量a的地址
}
int main()
{
int* p = test();// p就是一个野指针
return 0;
}
//当 test 函数执行完毕后,局部变量 a 的内存空间会被释放,但指针 p 仍然指向这块已经释放的内存区域。此时,p 就成了一个“野指针”
//修改
int* test()
{
static int a = 10; // 静态变量 全局都可用
return &a;
}
//或
int* test()
{
int* a = (int *)malloc(sizeof(int)); // 动态分配内存
if (a == NULL) {
// 处理内存分配失败的情况
return NULL;
}
*a = 10;
return a;
}
// 在 main 函数或其他地方使用完毕后,记得释放内存
free(p);
3.3避免野指针的方法:
1.指针初始化
int *p=NULL;
赋值为NIULL值得指针称为空指针,NULL指针是一个定位在标准库<stdio.h>中的值为零常量
#defined NULL 0
2.小心指针越界
3.指针指向空间释放及时置NULL
int a=10;
int *pa=&a;
printf("%d\n",*pa);
pa=NULL; //把pa指针置成NULL
4.避免返回局部变量的地址
5.指针使用之前检查有效性
四、指针和数组
"*",也称为解引用符号,其作用与&相反。
"*",后面只能跟指针(即地址)或指针变量,“&”后面跟的是普通变量(包括指针变量)。
4.1一维数组与指针
4.1.1指向一维数组的指针变量
所谓数组元素的指针就是数组元素的地址,可以用一个指针变量指向一个数组元素。
int a[10]={2.4,6,8,10,12,14,16,18,20};
int *p;//定义p为指向整型变量的指针变量
p=&a[0];// 把a[0]元素的对应地址赋值给指针变量p
int *q;
q=a;//理解: a[0]的地址赋给q
printf("%p",p);
printf("%p",q);
如下几个写法是等价的:
int *p;
p=&a[a]; //千万不要写成*p=&a[0];那就错了
int *p=&a[0];
int *p=a; //a不代表整个数组,所以这里不是将数组a赋值给p,而是代表数组元素a[0]的首地址
注意:因为数给名a保存的是数组首元素a[0]的地址,所以scanf函数中的输入项如果是数组名,不要再加地址符&。
//复习一下scanf() int a; &a
char arr1[10];
scanf("%s", arr1);//此时arr前不需要添加&
puts(arr1);
4.1.2使用指针访问数组的元素
如果指针变量p的初值为&a[0]则:
p+i和a+i 就是数组元素a[i]的地址。 或者说,它们指向a数组序号为i的元素。
*(p+i) 或 *(a+i) 是 p+i 或 a+i所指向的数组元素的值,即a[i]的值。
规律:
int a[10]={1,2,3,4,5};
int *p=&a[0];
a[0]: 表示 a[0]的数据值
a[0]的地址:&a[0]、p、a
a[0]的数据值:a[0]、*p,*a;
a[i]: 表示a[i]的数据值
a[i]的地址: &a[i]、p+i 、a+i;
a[i]的数据值:a[i] 、*(p+i)、*(a+i)
数组名字是数组的首元素地址,但它是一个常量 ******
*和[]效果一样,都是操作指针所指向的内存