野指针
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因
1、指针未初始化
//野指针
int main() {
int* p; //p是一个局部的指针变量,局部变量未初始化,默认是随机值
*p = 20; //非法访问内存
return 0;
}
2、指针越界访问
int main() {
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i <= 10; i++) {
*p = i;
p++;
}
return 0;
}
3、指针指向的空间释放
int* test() {
int a = 10;
return &a;
}
int main() {
int* p = test();
*p = 20;
return 0;
}//假设a的地址为0x0012ff40,在退出test函数时该空间就被释放了
//如果强行给0x0012ff40空间赋值,则报错
如何规避野指针
1、指针初始化
当前不知道初始化为什么地址时,直接初始化为NULL
2、小心指针越界
3、指针指向空间释放及时置NULL
4、指针使用之前检查有效性
指针运算
指针±整数
指针-指针
指针的关系运算
//指针加减整数
#define VALUES 5
int main() {
float values[VALUES];
float* vp;
for (vp = &values[0]; vp < &values[VALUES];) {
*vp++ = 0;
}
return 0;
}
//指针-指针
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", &arr[9] - &arr[0]);
//指针-指针得到两个指针之间元素个数
//指针-指针的前提:两个指针指向同一个空间
return 0;
}
//实例:求字符串长度
int my_strlen(char* str) {
char* start = str;
while (*str != '\0') {
str++;
}
return str - start;
}
//指针的关系运算
int main() {
for (vp = &values[VALUES]; vp > &values[0];) {
*--vp = 0;
}
return 0;
}
//简化
int main() {
for (vp = &values[VALUES-1]; vp >= &values[0]; vp--) {
*vp = 0;
}
return 0;
}
实际在绝大部分编译器上是可以顺利完成的,但我们应该避免这样写,因为标准并不保证它可行。
标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
指针和数组
//指针和数组
int main() {
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}
说明:数组名表示的是数组首元素的地址
二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?这就是二级指针。
//二级指针
int main() {
int a = 10;
int* pa = &a; //pa是指针变量,一级指针
int** ppa = &pa; //pa也是变量,&pa取出pa在内存中起始地址
//ppa就是二级指针变量
return 0;
}
指针数组
指针数组是数组
//指针数组
int main() {
int arr[10]; //整型数组--存放整型的数组
char ch[5]; //字符数组--存放字符的数组
int* parr[5]; //整形指针的数组
return 0;
}