一级指针,二级指针
一级指针
int a;
int *p ;
p=&a ;//也可以写作 *p = a;
p是a的地址, *p是a的值
&:取地址
*:解引用
为了加深理解找了个小例子
#include<stdio.h>
int a = 2, b = 3;
int * q;
void fun(int* p)
{
p = &b;
printf("%d\n", *p);
}
int main()
{
q = &a;
printf("%d\n",*q);
fun(q);
printf("%d\n",*q);
return 0;
}
上述例子输出为:
2
3
2
分析:q本身存的是a的地址,输出2,将q赋值给子函数的形参p后,p也指向了a,然后在函数内部又将p指向了b,于是函数内部输出3,但是不影响外部的q,q依然指向a,依然输出2。
那么现在来修改一下fun的内部代码
#include<stdio.h>
int a = 2, b = 3;
int * q;
void fun(int* p)
{
*p = b;//注意这里已经修改了!!!
printf("%d\n", *p);
}
int main()
{
q = &a;
printf("%d\n",*q);
fun(q);
printf("%d\n",*q);
return 0;
}
此时的输出为:
2
3
3
分析:q本身存储了a的地址,输出2,将q赋值给子函数的形参p后,p也指向了a,此时和上一个fun不一样的是,在函数内部对p解引用,并且将p指向的位置的值更改为b,就是将内存中存储的a变成了b,于是函数内部输出3,执行完之后回到主函数,q依然指向a那个位置,但此时内存里已经没有a了,a变成了b,所以输出的是3。
二级指针
int a;
int * p;
p = &a ;
int **q ;
q= &p ;
p是a的地址, * p是a的值
q是p的地址, * q是p的值,是a的地址, **q是 * p的值,是a的值;
二级指针的使用要比一级指针更加谨慎,尤其是在指针强转的时候,一不小心就指向了奇怪的地方。。。。
比如下面这段定义:
uint32_t x = 10 ;
uint32_t * a ;
a = &x ;
CustomType **b = (CustomType **)&a ;
如何通过b去输出变量x的地址和值?
首先a=&x,a的值就是x的地址, * a就是x的值
而b存储的是指针a的地址,即&a,且做了一次强制类型转换。
则*b就是对二级指针解引用,得到a,即&x,由此得到了x的地址,但由于a是uint32_t类型的指针,再对b进行解引用之后需要强转成uint32_t类型的指针,即(uint32_t *)(*b),这样才能精准的访问到a的值,即x的地址,再在前面加一个 * 就能访问到x的值了。
这里有个会弄混的误区,就是直接对b进行(uint32_t *)强转,没有做解引用,这其实是对a的地址的强制转换,并不是对a的强制转换,而a才是那个需要强制转化得到的指针。
指针数组和数组指针
其实听名字就能分清楚的,但总是说着说的会乱掉。。。。定义的时候一个不注意就是一团乱。。。。
指针数组
一个由很多个指针组成的数组。本质上是个数组,只是其中的元素是指向别的空间的指针。
例如由10个int型指针组成的数组:int *p[10];
这时候需要对数组中的每个指针规定指向,就可以访问到其他不同的内存空间。
数组指针
本质上是一个指针,指向一个数组。
例如一个指向长度为10的int型数组的指针:int( *p)[10];
这里需要注意的点就是,注意区分指向数组首元素的指针,和指向数组的指针,虽然值是一样的,但是前者储存的是数组首元素的地址,和数组无关。而后者存储的是数组的首地址,是和整个数组相关联的
下面举个例子:
指向数组首元素的指针:
int *p1 = b;
int a[5] = {1, 2, 3, 4, 5};
int *p2 = a;
p2这个指针仅仅只是指向了第一个元素,并非整个数组。本质上和p1一样
这里给p2+1再解引用,得到的是数组a中第二个元素的值,即 *(p2+1)=2;
指向数组的指针:
int temp[5] = {1, 2, 3, 4, 5};
int (*p)[5] ;
p = &temp;
这里要注意,temp是数组里第一个元素的地址,&temp才是整个数组的首地址
万万不可写成p=temp,二者虽然在值上一致,但含义完全不同,编译也会报错的
如果我们需要得到数组的第二个元素的值,按照上面普通指针的写法就完全错误了,因为这里的p+1,偏移量是整个数组而不是一个数组元素, 正确的写法应该是 * (*p+1)
指针的长度和指针类型和偏移量
指针的长度只和处理器的位数有关,指的是sizeof的结果,在32位系统中就是4字节,64位系统中就是8字节,和它的类型无关。
而指针加减1的操作和类型有关,比如一个int型指针,p+1的偏移量是4字节,而double类型的偏移量就是8字节。