C 语言 第五章 指针(7)
目录
野指针
什么是野指针
野指针的成因
① 指针使用前未初始化
② 指针越界访问
③ 指针指向已释放的空间
野指针的避免
1、指针初始化
练习:
2、小心指针越界
3、避免返回局部变量的地址
4、指针指向空间释放,及时置 NULL
5、指针使用之前检查有效性
二级指针(多重指针)
定义:
格式:
举例 1:
图示:编辑
举例 2:
关于数组与指针的互换示例:
野指针
什么是野指针
定义:
野指针:就是指针指向的位置是不可知(随机性,不正确,没有明确限制的)。
野指针的成因
① 指针使用前未初始化
指针变量在定义时如果未初始化,其值是随机的,此时操作指针就是去访问一个不确定的地址,所以结果是不可知的。此时 p 就为野指针。
在没有给指针变量显式初始化的情况下,一系列的操作(包括修改指向内存的数据的值)也是错误的。
int main() { int* p; *p = 10;危险的,指针变量p地址是随机的 把别的地址的值进行修改 //return 0;
}
② 指针越界访问
int main() { int arr[10] = {0}; int* p = arr; for (int i = 0; i <= 10; i++, p++) { *p = i; // i=10时越界 } return 0;
}
注:当 i=10 时,此时 *p 访问的内存空间不在数组有效范围内,此时 *p 就属于非法访问内存空间, p 为野指针。
③ 指针指向已释放的空间
int* test() { int a = 10; return &a;
}
int main() { int* p = test(); printf("%d", *p); return 0;
}
注:调用 test 函数将返回值赋给p , test 函数的返回值是局部变量 a 的地址。由于 a 只在 test 函数内有效,出了 test 函数其内存空间就被释放,也就意味着 a 的地址编号不存在,若将其赋值给 p ,导致 p 获取到的地址是无效的,此时 p 为野指针。
野指针的避免
1、指针初始化
定义指针的时候,如果没有确切的地址赋值,为指针变量赋一个 NULL 值是好的编程习惯。即
int *p = NULL;
注:赋为 NULL 值的指针被称为空指针, NULL 指针是一个定义在标准库 <stdio.h> 中的值为零的常量 #define
NULL 0
后面如果用到指针,再让指针指向具有实际意义的地址,然后通过指针的取值符号 ( * ) 改变其指向的内容。
练习:
#include<stdio.h>
int main() { int *p = NULL; // 空指针不要与未初始化的指针混淆 int b = 8; p = &b; // 显式赋值 *p = 100; printf("%d\n", *p); // 100 printf("%d\n", b); // 100 return 0;
}
2、小心指针越界
3、避免返回局部变量的地址
4、指针指向空间释放,及时置 NULL
int a = 10;
int* pa = &a;
printf("%d\n", *pa);
pa = NULL; // 把 pa 指针置成 NULL
printf("%d\n", pa);
5、指针使用之前检查有效性
if (pa != NULL) { // 进行使用
}
if (pa == NULL) { // 不进行使用
}
二级指针(多重指针)
定义:
- 一个指针变量 p1 记录一个变量的地址。
- 由于指针 p1 也是变量,自然也有地址,那么 p1 变量的地址可以用另一个指针 p2 来记录,则 p2 就称为二级指针。
- 简单来说,二级指针即一个指针变量的值是另外一个指针变量的地址,
- 通俗来说,二级指针就是指向指针的指针。
格式:
数据类型** 指针名;
举例 1:
int a = 10;
int* pa = &a; // pa 是一级指针
int** ppa = &pa; // ppa 是二级指针,类型为 int**
图示:

注: 进而推理,会有int*** pppa=&ppa;等情况,但一般这些情况一般不会遇到。
举例 2:
int main() { int var = 3000; int *ptr = &var; // 一级指针指向 var int **pptr = &ptr; // 二级指针指向 ptr int ***ppptr = &pptr; // 三级指针指向 pptr printf("Value of var: %d\n", var); printf("Value of ptr: %d\n", *ptr); // 解引用一次 printf("Value of pptr: %d\n", **pptr); // 解引用两次 printf("Value of ppptr: %d\n", ***ppptr); // 解引用三次 return 0;
}
关于数组与指针的互换示例:
void setvalue(int vals[], int len) { for (int i = 0; i < len; i++) { vals[i] = i * 10; }
} int main() { int nums[5] = {0}; // 数组初始化 setvalue(nums, 5); // 调用函数,传递数组名和简单变量 printf("调用函数后输出结果:\n"); for (int i = 0; i < 5; i++) { // 遍历数组元素 printf("nums[%d] = %d\n", i, nums[i]); } return 0;
}
传入整数数组与传入整数指针是同一回事,数组符号 [] 与指针符号 * 可互换,如:
void setvalue1(int *vals, int len) { int i; for (i = 0; i < len; i++) { vals[i] = i * 10; }
}