1.指针理解
核心:地址==指针
Cpu内有许多内存单元,每个内存单元的编号就是指针
2.指针变量和地址
2.1取地址操作符(&)
得到一个变量地址的操作符
2.2指针变量和解引用操作符(*)
2.2.1指针变量
取出的地址存放于指针变量中
2.2.2指针类型
把名字去掉以后就是指针变量的类型
eg:int a = 0;
int *p = &a;
p的类型就是int*,而p前面有*说明它是指针变量
2.2.3解引用操作符(*)
类比:知道一个房间的编号,如何使用房间内存放的物品
2.3指针变量的大小
指针变量的大小取决于地址的大小
32位平台下是4个字节
64个平台下是8个字节
指针变量的大小和类型无关,在相同平台下,大小都相同
3.指针变量类型的意义
3.1指针的解引用
int*类型指针解应用访问4个字节
char*类型指针解引用访问1个字节
3.2指针加减整数
根据指针类型可跳过字节多少
int*跳过4个字节
char*跳过1个字节
3.3void*指针
可以接收任意类型地址
不能直接进行指针的加减整数和解引用的运算
常用于泛编程
4.const修饰指针
4.1const修饰指针变量
分两种
1.const在*左边
const int*p = &a;
这个时候p就不能再赋其他地址
2.const在*右边
int* const p = &a;
这个时候就不能更改其中的内容,也就是不能再改变a的值
5.指针运算
5.1指针+-整数
数组在内存中连续存放,只要知道一个元素的地址,就可以知道后面的
5.2指针-指针
可以计算两个指针之间的元素个数,小地址-大地址就是负数,大地址-小地址就是正数
5.3指针的关系运算
6.野指针
概念:指针指向的位置是不可知的
6.1成因
1.未初始化
int * p ;
2.指针越界访问
在数组中,如果超出数组的范围,就会出现野指针
3.指针指向的空间释放
在自定义函数中,尤其注意栈帧空间的创建和销毁
6.2如何规避野指针
6.2.1指针初始化
6.2.2小心指针越界
6.2.3指针变量不断,使用时及时置NULL,使用前检查有效性
6.2.4避免返回局部变量的地址
7.asser断言
一般形式
assert(p......);
只要()内的条件不满足,程序就会报错
包含头文件assert.h
用#define NDEBUG注释
8.指针的使用
8.1传值调用
8.2传址调用
常被用于自定义函数中传递参数
9.数组名的理解
数组名就是数组首元素的地址
特例
eg:
arr+1跳过4个字节
&arr+1跳过40个字节
10.一位数组传参本质
本质上数组传参传递的是数组首元素的地址
所以,一维数组传参形参的部分可以写成数组的形式,也可以写成指针的形式
11.二级指针
指针变量也有地址
用来存放指针变量的地址的
就是二级指针
• *ppa 通过对ppa中的地址进⾏解引⽤,这样找到的是 pa , *ppa 其实访问的就是 pa .
• **ppa 先通过 *ppa 找到 pa ,然后对 pa 进⾏解引⽤操作: *pa ,那找到的是 a .
12.指针数组
是用来存放数组的指针
13.字符指针变量
14.数组指针变量
是用来存放数组的地址,能够指向数组的指针变量
15.二维数组传参的本质
回顾:二维数组可以理解为以每一行一维数组为元素的一维数组
所以二维数组传参本质上是传递了地址,传递的是第一行这个一维数组的地址
16.函数指针变量
用来存放函数的地址
17.函数指针数组
把函数的地址存到一个数组中,那个数组就叫做函数指针数组
基本形式
int (*parr1[3])();
18.回调函数
回调函数就是一个通过函数指针调用的函数