目录
一、指针基础知识
二、野指针
三、指针运算
四、二级指针
五、指针数组与数组指针
六、函数指针与函数指针数组
一、指针基础知识
什么是指针?
指针其实就是个用来存放地址的变量,定义为type + *。
指针大小?
32位平台(32个地址线)是4字节,64位平台(64个地址线)是8字节。
指针类型有哪些?
二、野指针
int main(){
int* p;
*p = 2; //解引用时会出现野指针问题
return 0;
}
(2)指针使用已经释放的空间
int mian(){
int *p = (int*)malloc(sizeof(int));
free(p);
*p = 2; //误用已经释放的内存,造成野指针问题
return 0;
}
(3)指针越界访问
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
如何规避野指针?
- 指针定义时进行初始化
- 小心指针越界
- 指针释放空间是置NULL
- 指针使用前检查其有效性
三、指针运算
我们先来看下指针和数组之间的关系。
数组名是什么?我们来看一个例子
#include <stdio.h>
int main()
{
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}
故int*p = arr 是可行的
(1)指针 +- 整数
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
int*p = arr;
p++;
在上面代码中指针p类型是int*类型,对p++实际是将指针p+sizeof(int)字节。++前p的值为数组第一个元素0,++后p的值为数组第二个元素1,故我们除了用下标访问的形式访问数组中的数据外也可通过这种方式来访问数组内的数据,如下:
int main(){
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int* p = arr;
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
printf("%d ", *(p + i));
}
return 0;
}
(2)指针 - 指针
指针 - 指针即代表两指针相隔几个元素,如下:
int main(){
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int* p1 = arr;
int* p2 = &arr[4];
printf("%d ", p2 - p1);
return 0;
}
四、二级指针
int main(){
int a = 10;
int* pa = &a;
int** ppa = &pa; //二级指针
return 0;
}
下面通过监视来更好理解二级指针:
从图中我们可以看出一级指针中存储的是变量的地址,二级指针存储的是一级指针的地址。更高级的指针同理。
想通过ppa找到变量a的值需要对其进行两次解引用操作,因*ppa是pa的值,pa中存储的是a的地址,故**ppa才是a的值。
五、指针数组与数组指针
不知道大家是否和我一样指针数组和数组指针在学的时候还是有点混淆的,下面来详细看一看。
指针数组:本质就是个数组,数组中元素类型是指针类型
定义:int *p [5]
元素类型:p首先和[ ]结合构成数组,我们只需要把他去掉之后就是它的元素类型。
数组指针:本质就是个指针,指针指向数组
定义:int (*p) [5]
元素类型:p首先和 () 结合构成指针,同样把他本身去掉之后就是它的元素类型。
说明:[ ]优先级要高于*号,当不加 () 时会首先和[ ]结合,反之会首先和*结合
理解:
六、函数指针与函数指针数组
函数指针:本质就是个指针,指针指向一个函数
定义:void (*pf) (int, int)
解释:和前面分析一样很容易知道,pf是一个指针指向返回值void类型,形参为均int类型的函数。
函数指针数组:本质就是个数组,数组中元素类型为函数指针
定义:void (*pf[5]) (int, int)
解释:pf为数组,数组中存储的元素类型为函数指针类型,返回值为void类型,形参均为int类型
理解: