关于指针这一节,让不少人又爱又恨,爱其对操作数据提供便利,恨其要是失去控制,要定位其原因要花很长时间
指针
指针,即为地址,就像是在某小区中,假如,某个人住在A区1306,那么A区1306就是这个人住得地址,当你访问这个地址时,就能找到这个人。
同样的,下面的代码:
int a= 10;
int *p = &a;
声明一个变量a,用p指向a,即p中存放了变量a的地址
通过p就能操作a。
同样的,既然p是一个地址,那么也可以有一个指针指向p,可以这样写
int a= 10;
int *p = &a;
int **q = &p;
同样的道理,q存放的是p的地址。
指针操作
C/C++常将地址当成整数来处理,但是,这并不意味着程序员可以对地址(指针)进行各种算数操作,两个指针的乘除,相加减都是没有意义的,合法的算数包括以下几种
- 指针与整数的加减(包括指针的自增和自减)
- 同类型指针间的比较
- 同类型的两指针相减
算数运算
指针加上一个整数的结果是另外一个指针,那这个指针是指向哪里呢?若一个字符指针加1,运算结果产生的指针指向内存下一个字符,但,int,short,double,float等都不止一个字节,如果你将一个指向float的指针加1,将会发生什么?
事实上,一个指针与一个整数进行算法运算是,整数在执行加法运算前始终会根据合适的大小进行调整。
这个合适的大小就是指针所指向类型的大小,如执行int类型变量,那么合适大小就是int字节大小(通常是4字节)的整数倍调整
下面是指针运算结果表
表达式 | 假定p是指向…的指针 | 而且*p的大小是 | 增加到指针的值 |
---|---|---|---|
p+1 | char | 1 | 1 |
p+1 | short | 2 | 2 |
p+1 | int | 4 | 4 |
p+1 | double | 8 | 8 |
p+2 | char | 1 | 2 |
p+2 | short | 2 | 4 |
p+2 | int | 4 | 8 |
p+2 | double | 8 | 16 |
指针数组和数组指针
就从字面上看,所谓指针数组,说明是是个数组,数组里面的类型是指针,如,一个包含8个int*类型的数组,数组的定义是:
int *a[8]
包含的元素是这样的:
很多地方为了便于理解,将上述定义这样写:
int* a[8]
一定一个数组a,元素是int*,上述的*靠近int
所谓数组指针,说明是一个指针,只是它指向了一个数组
一个指向10个元素整形数组的指针这样定义:
int (*p)[10];
由于[]的优先级高于*,所以必要要加括号 (*p)
二维数组的数组名是一个数组指针,若有:
int a[4][10];
int (*p)[10];
p = a;
则如下图:
图中p可被替换为a。但需要注意的是a是常量,不可以进行赋值操作
若有代码:
int a[10];
int (*p)[10] = &a; //此处是&a,不是a, &a的类型是int(*)[]
int *q = a;
则如下图
p与q虽然都指向数组的第一个元素,但由于p的类型和q的类型不同 ,p是指向10个元素整形数组的指针,*p的大小是10个字节,所有p+1跳过40个字节
q是指向整形的指针,*q的大小是4个字节,所以q+1跳过4个字节
指针运算在数组的应用
用指针可以方便访问数组,由于指针可以随时指向任意类型的内存块,因此要注意指针的指向是否是数组中的某个元素
欢迎关注我的微信公众号: