指针概述
指针存放的都是首地址。
1、定义与初始化
形式:<数据类型>* <变量名> = <地址>;
int a = 10;
int *p = &a;
指针的类型不同,p++时的偏移地址量不同,偏移地址 = sizeof(类型)Byte
注意点:
- 指针的类型要与数据的类型保持一致,a为int,那么p就是int*," * " 称为指针运算符
- 指针应该赋值地址,&为取地址符,存放的是数据的首地址
- 指针变量不能赋值普通整数(0除外),不能赋值p=0x1234,而应该赋值p=(类型*)0x1234
2、目标与解引用
目标:指针指向的内存区域的数据。上述中,a就是目标。
解引用(间接访问):使用*p对目标进行访问," * "称为解引用。上述中*p就是解引用
注意:在使用(*p)++时,需要加括号。" * "的优先级低于 " ++ " " -- "
对于上述代码,指针的几种方式有:p、*p、&p,关系如下:
- p: 指针变量, 它的内容是地址量
- *p: 指针的目标,它的内容是数据
- &p: 指针变量占用的存储区域的地址,是个常量
3、指针大小与寻址空间
指针的大小与系统的位数有关。
- 32位的系统有32根地址线,因此指针大小为32位,4字节
- 64位的系统有64根地址线,因此指针大小为64位,8字节
注意:指针存放的是地址,地址的大小是固定的。不论是什么类型的指针,大小都为4或8字节。
寻址空间与指针的位数有关。
- 32位的指针大小可以寻址0~2^32-1范围
- 64位的指针大小可以寻址0~2^64-1范围
4、空指针
空指针并不是指没有赋值的指针,而是赋值为NULL的指针。NULL就是(void*)0
使用空指针的原因:
- 指针在定义时没有初始值,值是不确定的。给一个空指针可以防止野指针的出现。
- 空指针指向0,这个地址不允许访问,访问一定出现段错误,因此可以很快发现指针使用错误
良好的编程习惯:
- 在定义指针时,要么是赋值非空指针,要么是赋值NULL,防止野指针出现
- 在函数传入指针参数时,首先判断是否为空,防止后续产生段错误。
5、野指针
野指针指的是指向了一个不确定空间的指针。
有一些野指针在编译上不会产生任何问题,逻辑上却会产生很严重的莫名奇妙的bug
产生野指针的原因:
- 指针没有初始化,比如只定义了int* p;而没有赋值NULL或其他值
- 指针越界访问,比如char a[3]最大索引为2,然而去访问了a[3],产生了越界,就是野指针
- 指针指向空间被释放,比如malloc开辟的空间,free之后再去访问,这就是野指针
指针运算
1、指针±常数
指针±常数的符号有:+、- 、++、--
指针±常数后的值与指针的类型有关,参与运算的是指针保存的地址。
- 运算结果=当前位置 + 常数 * sizeof(类型)
对如下程序进行分析:
int a[5] = {1,2,3,4,5};
int* p = a;
p++;
这里的p为a的首地址,假设为0x00。p++之后,p的值 = 0x00+1*sizeof(int),这个值就是&a[1]
注意:
- 这里的p应该与a类型一致,int对应int,不能用char* p去访问int a[5]
- " 指针+常数 "代表指针向高地址移动," 指针-常数 "代表指针向低地址移动
2、指针-指针
指针-指针运算需要两个参与运算的指针的类型相同,这才是有效运算。运算结果代表这两个指针之间相差了多少个元素。比如上述代码,p++之后值为0x04,p的值为0x00,相减之后并不为4,而是为1,说明p++与p之间相差了一个int元素。代码验证如下:
3、自加自减运算注意点
" ++ "、" -- "的运算优先级比" * "的优先级要高,所以要注意运算的结合顺序。
下面以一个小代码为基础分析*p++、(*p)++、++p、++*p的含义
int a[5] = {1,2,3,4,5};
int* p = a;
3.1 *p++含义
p++先运算,但++为先用后加,所以运算的值是*p,结果为1。之后p指针+1,指向2
训练:分析*p++ = 3的值
p++先结合,先用再加,所以当前*p=1,之后将3进行赋值,所以a[0]变为3,最后指针+1,指向2
3.2 (*p)++含义
*p先运算,相当于把1取出来,之后再++。同样是先用再加,所以运算值为1,之后1+1变为2
3.3 *++p含义
++p先结合,先加后用。所以运算的值是*(p+1),结果为2,最终p指向2
3.4 ++*p含义
这时++与*已经不在有优先级的事情,因为没有运算的考虑点。在前面*p++时,我们不知道是先和*还是先和++结合,所以考虑优先级。对于++*p,p只能和*结合,所以含义如下:
*p结合之后再++,是先加再用,所以运算结果是1+1=2,最终a[0]=2,*p依旧指向a[0]
4、指针比较
指针可以进行比较,运算符有:>、<、==、!=
指针比较的含义:
- 与0比较,判断指针是否为空指针NULL
- 与正常指针比较,存放地址大的指针>存放地址小的指针,如p1=&a[0],p2=&a[1],则p1<p2