1.野指针
野指针是指针指向的位置是不可知的(随机的,不正确的,没有限制的)。
原因:
(1)指针未初始化
#include <stdio.h>
int main() {
int a; // 局部变量不初始化,默认是随机值
int* p; // 局部指针变量不初始化,默认也是随机值
*p = 100;
printf("%d", *p);
return 0;
}
(2)指针越界访问
#include <stdio.h>
int main() {
int arr[5] = { 0 };
int* p = arr;
for (int i = 0; i < 8; i++) {
// 当指针指向的范围超出数组arr的范围时,p就是野指针。
p++;
}
return 0;
}
(3)指针指向的空间释放
int* test() {
int arr[10] = { 0 };
return arr;
}
int main() {
int* p = test();
printf("%d\n", *(p+1));
}
如何规避?
① 指针初始化, int* p = NULL
② 小心指针越界
③ 指针指向空间释放,及时置空
④ 指针使用之前检查有效性
2.指针的计算
(1)指针+-整数
#include <stdio.h>
int main() {
int arr[5] = { 10,12,18,92,64 };
int* p = arr;
int size = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < size; i++) {
/*printf("%d\n",*(arr+i));*/
printf("%-4d", *p);
p = p + 1;// p++
}
}
(2)指针-指针
#include <stdio.h>
int main() {
int arr[5] = { 13,34,21,38,49 };
int res = &arr[4] - &arr[0];
printf("%d\n", res);
return 0;
}
(3)指针的关系运算
#include <stdio.h>
int main() {
float values[5] = { -1 };
float* vp;
for (vp = &values[5]; vp > &values[0];) {
*--vp = 0;
}
return 0;
}
标准规定: 允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一 个元素之前的那个内存位置的指针进行比较。
3.指针和数组
#include <stdio.h>
int main() {
int arr[] = { 1,2,3,4,5,6,7 };
int* p = arr; // p存放的是数组首元素的地址
int size = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < size; i++) {
printf("&arr[%d]=%p <-----> p+%d = %p\n", i, &arr[i], i, p + i);
}
}
p+i 其实就是数组arr下标为i的地址,因此可以通过指针来访问数组。
!!例外:
&数组名中,数组名不是首元素的地址,数组名表示整个数组,&数组名,取出的是整个数组的地址。
sizeof(数组名) 数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小。
4.二级指针
#include <stdio.h>
int main() {
int a = 10;
printf("&a=%p\n", &a);
int* pa = &a;
printf("&pa=%p\n", &pa);
int** ppa = &pa; // 二级指针
printf("&ppa=%p\n", &ppa);
return 0;
}
对于二级指针的运算有:
*ppa通过对ppa地址进行解引用,找到pa的值
**ppa先通过*ppa找到pa,然后对pa进行解引用操作:*pa,找到a。
5.指针数组
指针数组是存放指针的数组
#include <stdio.h>
int main() {
int a = 1;
int b = 2;
int c = 3;
int* pa = &a;
int* pb = &b;
int* pc = &c;
int* arr[3] = { pa,pb,pc }; // 指针数组
// 遍历指针数组
for (int i = 0; i < 3; i++) {
printf("%p:%d\n", arr[i], *arr[i]);
}
return 0;
}