一.指针变量
用于存放一个数据的地址的变量
内存大小根据环境而定 64位机器八字节 32位机器4字节(与类型无关)
创建语法
int* p = &(变量)
int是类型 *表明p是指针
同时还有二级指针即指向指针变量的指针
int** p1 = &p
二.取地址操作符和解引用操作符
取地址操作符&
int a = 0;
int* p = &a; //取得变量a的地址存放进指针变量p中
解引用操作符*
*p = 0; //取得p存放的地址处的数据
二级指针 **p
三.指针类型的意义
指针类型决定了一次能操作几个字节
如char* 一字节
int* 四字节
指针可加减整数实现指向移动
char*p = 00000001 p +1 = 00000002
int*p2 = 00000001 p+1 = 00000005
指针类型决定了你向后走一步移动的距离
指针相减可得到连续内存空间下的元素的个数可计算数组元素个数
注:void* 型也叫泛型指针 可以接受任意类型的地址 不能进行加减整数运算
可用于函数接收不同类型的指针参数
四.使用const修饰指针变量
const char* p 指针指向可以修改但是指针指向的内容无法修改
char * const p 指向内容可以修改 指向无法修改
const char * const 指向内容与指向均不可修改
五.数组 数组指针 指针数组 函数指针 转移表
1.数组
数组名就是数组首元素地址
有特殊情况 sizeof(arr)中arr代表整个数组
&arr 得到的是整个数组的地址 加减整数也是以整个数组为单位
arr[i] 可以看作*(arr+i) 当然也可写成i[arr]
编译器在处理arr[i]时是看作首元素地址加偏移量求出地址再解引用的
arr[m][n] 可看作 *(*(arr+m)+n)
2.数组指针
顾名思义即指向一个数组的指针
[ ]优先级高于* 所以要加括号否则就是指针数组
语法: int (* parr)[10]
parr是指针变量名
int 数组类型
[10] 是元素个数
变量类型可看作是int(* )[]
3.指针数组
元素为指针的数组
语法: int* arr[]
可看作是元素类型为int* 的数组
4.函数指针
指针变量中存放的是函数的地址
如有一函数
int sub(int a,int b)
{ return a-b }
创建变量
int (* psub)(int a,int b) = &sub 也可是sub函数名也可代表函数地址
使用函数方法 (* psubh)(a,b);
5.转移表
有时我们有多个类似的函数
如实现计算器对两个数字加减乘除
我们可以将计算函数的地址存放进一个指针数组中
这个指针数组就叫转移表 我们可以更方便的调用多个函数
如函数 sub sum mul div
创建指针数组
类型可看作是 int (* )(int a,int b)
int (* parr[4])(int a,int b) = {sub,sum,mul,div}
如何调用呢?
与函数指针类似 (*parr[0])(a,b)
六.野指针
指向未知的指针
可能出现原因 未初始化 越界访问 指向的空间释放
规避野指针
创建变量时初始化
不使用及时置空 即赋值NULL 空指针
使用前检查有效性 为空指针则不再使用或重新赋值
可以利用assert
需要头文件assert.h
语法assert(条件)
作用不满足条件终止运行用于程序调试
assert(p!=NULL)
如果你不想assert再起作用可以直接在开头定义一个宏 #define NOBUG
七.传值调用和传址调用
区别:前者无法改变实参 后者可以改变实参