3. *( *(p2+1)+1)反汇编
//C语言代码: short** p2; printf("%d",*(*(p2+1)+1));
我们还是直接来到反汇编窗口来观察:
//反汇编代码: mov eax,dword ptr [ebp-4] mov ecx,dword ptr [eax+4] movsx edx,word ptr [ecx+2]
大家可以从下面这张图中来理解:
该图中,蓝色为未作任何操作时二级指针示意图,较细箭头为给p2+1时的指向,加粗箭头为最终指向
我们来逐步分析对*( *(p2+1)+1)取值的过程:
1.首先取出指针变量p2中存取的数据,放入eax
2.将eax内存放的数据当作地址,在该地址基础上+4,取出该地址内存放的数据,放入ecx(第一次取出的数据,是一个地址,指向第一个一级指针,如图所示,将二级指针+1,实际上就是要指向本来要指向的一级指针(一级指针1)的下一个(一级指针2),由于一级指针占据4个字节,所以要在二级指针内存放的数据+4(4 * 1))
3.将ecx中的值+2,再当作一个地址,取出该地址中存放的数据,放入edx(由于一级指针2本来指向的是数据2(short类型,占据2字节),所以要在一级指针内存放的地址上+2(2 * 1))
4. *( *(p2+2)+3)
这里其实是前三个的运用,为了加深理解,我们来定义char**类型的二级指针。
//C语言代码 char** p2; printf("%d",*(*(p2+2)+3));
//反汇编代码 mov eax,dword ptr [ebp-4] mov ecx,dword ptr [eax+8] movsx edx,byte ptr [ecx+3]
我们继续以画内存图的方式来为大家讲解:
该图中蓝色箭头为二级指针未作任何操作时的指向,较细橙色箭头为对二级指针操作后的指向,较粗箭头为对一级指针操作后的指向。
我们来逐步分析对*( *(p2+2)+3)取值的过程
1.取出二级指针变量p2中的数据,放入eax中
2.将eax中的值+8,将得到的值看作地址,取出该地址中存放的数据,放入ecx(第一次取出的地址指向一级指针,所以对二级指针+2的操作实际上是让改二级指针指向原本指向的一级地址再向后便宜两个一级指针,所以就是二级指针内存放的数据+8(4 * 2))
3.将ecx中的值+3,将得到的值看作地址,取出该地址内存取的数据,放入edx(由于ecx内存取的是一个地址(可以看作一级指针),指向char类型的数据,所以对一级指针+3的操作实际上是对一级指针内存放的数据+3(3 * 1))。
三级指针
我们先来了解一下三级指针:
//C语言代码: char a=1; char* p1=&a; char** p2=&p1; char*** p3=&p2;
这里我们定义一个char类型的变量a,定义一个char*类型的变量(一级指针)p1存放a的地址,定义一个char * *类型的变量(二级指针)存放p1的地址,再定义一个char * * *类型的变量存(三级指针)放p2的地址。
//反汇编代码: mov byte ptr [ebp-4],1 lea eax,[ebp-4] mov dword ptr [ebp-8],eax lea ecx,[ebp-8] mov dword ptr [ebp-0Ch],ecx lea edx,[ebp-0Ch] mov dword ptr [ebp-10h],edx
根据反汇编分析:
将1存进a[ebp-4]中
将a[ebp-4]的地址存入eax,将eax存入p1[ebp-8]中————>一级指针
将p1[ebp-8]的地址存入ecx,将ecx存入p2[ebp-0ch]—————>二级指针
将p2[ebp-0ch]的地址存入edx,将edx存入p3[ebp-10h]——————>三级指针
1. 数据宽度
我们通过C语言sizeof函数可以得到三级指针所占据的数据宽度:
char*** a; printf("%d",sizeof(a);
我们可以看到在程序输出框里输出:
4
所以三级指针占据4个字节存储空间,在C语言编译器中,我们有数据类型之分,但是实际在电脑内存中,内存条根本没有数据类型之分,它只负责存储数据。
2. 三级指针++,–,加或减一个整数运算
//C语言代码: char*** a=(char***)100; printf("%d",a++);
我们能够观察到在程序输出窗口输出:
104
char ***内存储的是一个char **类型变量的地址,对char ***类型+1,实际上是要char ***指向原本指向数据的下一个数据,而char **类型占据4个字节,所以要在原本char ***基础上+4(4 * 1)。
反汇编代码:
//反汇编代码: mov dword ptr [ebp-4],64h mov eax,dword ptr [ebp-4] add eax,4
我们来分析整个过程:
定义了一个char ***类型的变量,通过强制转换类型将100转换为char ***类型。然后对该变量里存储的值+4(在内存并不认为它是地址,只是编译器和我们认为它是地址,内存只负责存储,在内存眼里所有数据都一样)。
3. 三级指针反汇编
1. *(*p3)反汇编
C语言代码:
char*** p3; printf("%d",*(*p3));
我们知道在带 *的数据类型前面加 *得到的数据类型就是原本的类型去掉一个 *,所以我们这里取到了一级指针,并没有取到一级指针所指的空间里所存储的数据。
反汇编代码:
mov eax,dword ptr [ebp-4] mov ecx,dword ptr [eax] mov edx,dword ptr [ecx]
我们来逐步分析对*(*p3)取值的过程:
1.取出变量pa[ebp-4]内存储的数据,放入eax
2.将eax中的数据当作地址,取出该地址内存储的数据,放入ecx
3.将ecx中的数据当作地址,取出该地址中存储的数据,放入edx
2. *( *(*p3))反汇编
C语言代码:
char*** p3; printf("%d",*(*(*p3)));
反汇编代码:
mov eax,dword ptr [ebp-4] mov ecx,dword ptr [eax] mov edx,dword ptr [ecx] movsx eax,byte ptr [edx]
我们来逐步分析对*( *(*p3))取值的过程:
1.取出p3[ebp-4]中的数据,放入寄存器eax
2.将寄存器eax中存储的数据当作地址,取出该地址中存储的数据,放入寄存器ecx
3.将寄存器ecx中存储的数据当作地址,取出该地址中存储的数据,放入寄存器edx
4.将寄存器edx中存储的数据当作地址,取出该地址中存储的数据,放入寄存器eax
3. *( *( *( *p3+1)+2)+3)反汇编
C语言代码:
char*** p3; printf("%d",*(*(*(p3+1)+2)+3));
反汇编代码:
mov eax,dword ptr [ebp-4] mov ecx,dword ptr [eax+4] mov edx,dword ptr [ecx+8] movsx eax,byte ptr [edx+3]
我们来逐步分析对 *( *( *(p3+1)+2)+3)取值的过程:
由于此过程有点繁琐,我才用画内存图的方法带大家了解:
图中,蓝色箭头为未作任何操作时,三级指针的分别指向,较细橙色箭头为+1操作后三级指针指向的变化,较粗橙色箭头为+2操作后二级指针指向变化,绿色箭头为+3操作后一级指针指向的不安话
1.取出p3[ebp-4]中的数据,放入寄存器eax
2.将eax中存放的数据+4后当作地址,取出该地址中存放的数据,放入寄存器ecx(因为给变量p3本身+1,就是要三级指针指向原本指向的下一个数据,而三级指针指向的是二级指针类型,占据4个字节,所以给三级指针+1的操作事实上是给三级指针内存放的数据+4(4 * 1)
3.将寄存器ecx中的值+8后当作地址,取出该地址中存放的数据,放入寄存器edx(给二级指针+2的操作,就是要二级指针指向原本指向数据向再后偏移2个数据,所以事实上就是给二级指针内存放的数据+8(4 * 2)
4.将寄存器edx中存放的值+3后当作地址,取出该地址中存放的数据,放入寄存器eax(给一级指针+3的操作,就是要让指针指向原本指向数据再向后偏移三个数据,而此一级指针指向的数据为char类型,所以给该一级指针+3的操作,事实上是给该一级指针内存放的数据+3(1 * 3)
4. p3[1][2][3]反汇编
C语言代码:
char*** p3; printf("%d",p3[1][2][3]);
反汇编代码:
mov eax,dword ptr [ebp-4] mov ecx,dword ptr [eax+4] mov edx,dword ptr [ecx+8] movsx eax,byte ptr [edx+3]
我们来与*( *( *(p3+1)+2)+3的反汇编代码做个比较,发现它俩的反汇编代码竟惊人地相同!
在讲二级指针时我们已经讲过这个知识点,我们在这里就不再啰嗦了。
直接给出结论:
*(*(*(*(*(p+m) +n) +i) +j) +k)与p[m][n][i][j][k]可以互换
OK今天我们就学习到这里,当然希望大家可以指出此篇笔记的不足或者错误之处,当然希望我们能够共同学习,共同进步!!!