指针(六)
- 指向指针的指针:多级指针
- 指向数组的指针:数组指针
一、指向指针的指针:多级指针
1.*()和[]
定义几个不同级别的指针类型的数据
1 char* p1;
2 char** p2;
3 char*** p3;
4 char**** p4;
5 char***** p5;
6 char****** p6;
7 char******* p7;
1)*运算
代码:
1 printf("%d",*p1);
反汇编:
结论:
*运算的本质是取指针变量的值,利用这个值作为地址来寻址获取结果;
代码:
1 printf("%d",*(p1+0));
分析:
根据指针类型的特性,p1+0所得的类型还是char*类型,
并且所得的值要加上为去掉一个*后的类型的宽度乘以所加的数,而char的宽度是1,结果还是和原来一样;
反汇编和*P1没有区别:
结论:*(p1) ==*(p1+0)
2)[]运算
*(p1+0)可以用另一种写法:p1[0]
1 printf("%d",p1[0]);
反汇编:
分析:
*(p1+0)和p1[0]生成的反汇编代码完全一样;
结论:
*(p1+0) == p1[0]
代码:
1 printf("%d",*(p1+2));
2 printf("%d",p1[2]);
反汇编:
分析:
*(p1+2)是用p1+2所得的值来寻址:p1+(char*去掉一个*后的类型的宽度也就是char=1)x2;
*(p1+2)的反汇编和p1[2]完全一样;
结论:
*(p1+2) == p1[2]
3)多级指针
p2的类型是char**,也就是二级指针;
凡是带*的类型的变量都可以进行*运算;
*运算后的类型为原来的类型去掉一个*;
代码:
1 printf("%d",*(*(p2)));
反汇编:
分析:
取p2的值,利用p2的值寻址,利用地址处的值为地址再次寻址;
代码:
1 printf("%d",*(*(p2+0)+0));
反汇编:
分析:
*(p2+0) == *p2,经过*计算后类型变化:char** ->char*;
*(*p2+0) == *(*p2),因为*p2位char*类型,而char*类型的特性,加上一个整数等于加上去掉一个*后的类型的宽度乘以整数,也就是0,结果还是*p2;
结论:
*(*(p2+0)+0) == *(*p2)
代码:
1 printf("%d",*(*(p2+1)+2));
2 printf("%d",p2[1][2]);
反汇编:
分析:
p2是char**类型,根据指针类型的特性,p2+1相当于加上去掉一个*的类型的宽度乘以1;
也就是char*的宽度乘以1,又因为所有带*的类型宽度都是4,因此生成的反汇编寻址时为[eax+4];
同理,第二次寻址时的反汇编是[ecx+2];
*(*(p2+1)+2)生成的反汇编和p2[1][2]完全一样;
结论:
*(*(p2+1)+2) == p2[1][2];
4)总结:
1 *(p + i) = p[i]
2 *(*(p + i) + k) = p[i][k]
3 *(*(*(p + i) + k) + m) = p[i][k][m]
4 *(*(*(*(*(p + i) + k) + m) + w) + t) = p[i][k][m][w][t]
*() 与 []可以相互转换
2.实例
1 char** p;
2
3 printf("%d",*(p+1)[2]);
4 printf("%d",*(*(p+1)+2));
反汇编:
分析:
*(p+1)[2] != *(*(p+1)+2)
因为[]的运算优先级要高于*,先计算p+1移动4个字节;
然后计算(p+1)[2],相当于以p+1指向的地址作为首地址的数组,移动2*4=8个字节,所以为[eax+c];
最后做*运算;
也就是说:*(p+1)[2] == *(*(p+1+2));
二、指向数组的指针:数组指针
结构体指针 ->存了一个地址,该地址指向一个结构体;
指针的指针 ->存了一个地址,该地址指向一个指针;
数组指针 ->存了一个地址,该地址指向一个数组;
1)数组指针的特性
和普通指针的特性差不多:
- 宽度为4;
- 可以++、--;
- 可以加减一个整数;
2)使用数组指针
利用指针数组遍历:
3)数组指针和指针数组的区别
int *p[5] 与 int (*p)[5] 有什么区别?
原因:
[] 的优先级高于* 所以先组合成p[5]数组 再由int *说明 数组存储的类型 == int* p[5];
() 的优先级高于[] 所以*先p先组合成指针 再由int[5]说明数组的宽度