反汇编:指针数组和数组指针
前言:作为指针数组和数组指针的学习
指针数组
第一种写法
代码如下:
#include<stdio.h> int main(){ //指针数组 char arr[3][10] = { "aaaaa", "bbbbb", "ccccc" }; printf("%s",arr[1]); }
反汇编如下:
0040D440 >/> \55 PUSH EBP 0040D441 |. 8BEC MOV EBP,ESP 0040D443 |. 83EC 60 SUB ESP,60 0040D446 |. 53 PUSH EBX 0040D447 |. 56 PUSH ESI 0040D448 |. 57 PUSH EDI 0040D449 |. 8D7D A0 LEA EDI,DWORD PTR SS:[EBP-60] 0040D44C |. B9 18000000 MOV ECX,18 0040D451 |. B8 CCCCCCCC MOV EAX,CCCCCCCC 0040D456 |. F3:AB REP STOS DWORD PTR ES:[EDI] 0040D458 |. A1 2C204200 MOV EAX,DWORD PTR DS:[??_C@_05NHMN@aaaaa?$AA@] ; 将保存字符串的地址四个字节赋值给eax 0040D45D |. 8945 E0 MOV DWORD PTR SS:[EBP-20],EAX ; 将eax赋值给ebp-20 0040D460 |. 66:8B0D 30204>MOV CX,WORD PTR DS:[422030] ; 除了那四个字节之后存储字符串的地址中的双字节赋值给cx 0040D467 |. 66:894D E4 MOV WORD PTR SS:[EBP-1C],CX ; 也就是把aaaaa最后一个a的值赋值给ebp-1c,以0结尾 0040D46B |. 33D2 XOR EDX,EDX ; 清空edx 0040D46D |. 8955 E6 MOV DWORD PTR SS:[EBP-1A],EDX 0040D470 |. A1 24204200 MOV EAX,DWORD PTR DS:[??_C@_05GKCJ@bbbbb?$AA@] 0040D475 |. 8945 EA MOV DWORD PTR SS:[EBP-16],EAX 0040D478 |. 66:8B0D 28204>MOV CX,WORD PTR DS:[422028] 0040D47F |. 66:894D EE MOV WORD PTR SS:[EBP-12],CX 0040D483 |. 33D2 XOR EDX,EDX 0040D485 |. 8955 F0 MOV DWORD PTR SS:[EBP-10],EDX 0040D488 |. A1 1C204200 MOV EAX,DWORD PTR DS:[??_C@_05BHF@ccccc?$AA@] 0040D48D |. 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX 0040D490 |. 66:8B0D 20204>MOV CX,WORD PTR DS:[422020] 0040D497 |. 66:894D F8 MOV WORD PTR SS:[EBP-8],CX 0040D49B |. 33D2 XOR EDX,EDX 0040D49D |. 8955 FA MOV DWORD PTR SS:[EBP-6],EDX ; 清空ebp-6的高位两字节 0040D4A0 |. 8D45 EA LEA EAX,DWORD PTR SS:[EBP-16] ; 取bbbbb的字符串赋值给eax 0040D4A3 |. 50 PUSH EAX ; /<%s> 0040D4A4 |. 68 0C244200 PUSH OFFSET my.??_C@_02DILL@?$CFs?$AA@ ; |format = "%s" 0040D4A9 |. E8 82020000 CALL my.printf ; \printf
第二种写法
代码如下:
#include<stdio.h> int main(){ //指针数组 //还可以这样表示 //相当于定义为arr[][10] char* arr[10] = { "aaaaa", "bbbbb", "ccccc" }; printf("%s",arr[1]); }
反汇编如下:
0040D440 >/> \55 PUSH EBP 0040D441 |. 8BEC MOV EBP,ESP 0040D443 |. 83EC 68 SUB ESP,68 0040D446 |. 53 PUSH EBX 0040D447 |. 56 PUSH ESI 0040D448 |. 57 PUSH EDI 0040D449 |. 8D7D 98 LEA EDI,DWORD PTR SS:[EBP-68] 0040D44C |. B9 1A000000 MOV ECX,1A 0040D451 |. B8 CCCCCCCC MOV EAX,CCCCCCCC 0040D456 |. F3:AB REP STOS DWORD PTR ES:[EDI] 0040D458 |. C745 D8 2C204>MOV DWORD PTR SS:[EBP-28],OFFSET my.??_C@_05NHMN@aaaaa?$AA@ ; 将保存字符串的地址赋值给ebp-28中 0040D45F |. C745 DC 24204>MOV DWORD PTR SS:[EBP-24],OFFSET my.??_C@_05GKCJ@bbbbb?$AA@ ; 将保存字符串的地址赋值给ebp-24中 0040D466 |. C745 E0 1C204>MOV DWORD PTR SS:[EBP-20],OFFSET my.??_C@_05BHF@ccccc?$AA@ ; 将保存字符串的地址赋值给ebp-20中 0040D46D |. B9 07000000 MOV ECX,7 ; ecx赋值为7 0040D472 |. 33C0 XOR EAX,EAX ; 清空eax 0040D474 |. 8D7D E4 LEA EDI,DWORD PTR SS:[EBP-1C] ; ebp-1c的地址赋值给edi 0040D477 |. F3:AB REP STOS DWORD PTR ES:[EDI] ; 初始化00000000 0040D479 |. 8B45 DC MOV EAX,DWORD PTR SS:[EBP-24] ; 将存储bbbbb的地址赋值给eax 0040D47C |. 50 PUSH EAX ; /<%s> 0040D47D |. 68 0C244200 PUSH OFFSET my.??_C@_02DILL@?$CFs?$AA@ ; |format = "%s" 0040D482 |. E8 A9020000 CALL my.printf ; \printf 0040D487 |. 83C4 08 ADD ESP,8 0040D48A |. 5F POP EDI 0040D48B |. 5E POP ESI 0040D48C |. 5B POP EBX 0040D48D |. 83C4 68 ADD ESP,68 0040D490 |. 3BEC CMP EBP,ESP 0040D492 |. E8 59020000 CALL my.__chkesp 0040D497 |. 8BE5 MOV ESP,EBP 0040D499 |. 5D POP EBP 0040D49A \. C3 RETN
总结:
1、第一种方式:赋值的是字符串的字符数据
2、第二种方式:赋值的是字符串的地址
数组指针
代码如下:
#include<stdio.h> int main(){ int arr[] = {1,2,3,4,5,6,7,8,9,0}; //一维数组 int(*px)[2][2] = (int (*)[2][2])arr; printf("%d\n",(*px)[1][1]); px++; printf("%d\n",(*px)[1][1]); return 0; }
反汇编如下:
0040D756 |. F3:AB REP STOS DWORD PTR ES:[EDI] 0040D758 |. C745 D8 01000>MOV DWORD PTR SS:[EBP-28],1 ; 1 0040D75F |. C745 DC 02000>MOV DWORD PTR SS:[EBP-24],2 ; 2 0040D766 |. C745 E0 03000>MOV DWORD PTR SS:[EBP-20],3 ; 3 0040D76D |. C745 E4 04000>MOV DWORD PTR SS:[EBP-1C],4 ; 4 0040D774 |. C745 E8 05000>MOV DWORD PTR SS:[EBP-18],5 ; 5 0040D77B |. C745 EC 06000>MOV DWORD PTR SS:[EBP-14],6 ; 6 0040D782 |. C745 F0 07000>MOV DWORD PTR SS:[EBP-10],7 ; 7 0040D789 |. C745 F4 08000>MOV DWORD PTR SS:[EBP-C],8 ; 8 0040D790 |. C745 F8 09000>MOV DWORD PTR SS:[EBP-8],9 ; 9 0040D797 |. C745 FC 00000>MOV DWORD PTR SS:[EBP-4],0 ; 0 0040D79E |. 8D45 D8 LEA EAX,DWORD PTR SS:[EBP-28] ; 数组的首地址赋值给eax,eax就为0012FF58 0040D7A1 |. 8945 D4 MOV DWORD PTR SS:[EBP-2C],EAX ; 将存储数组的首地址赋值给ebp-2c指向的值 0040D7A4 |. 8B4D D4 MOV ECX,DWORD PTR SS:[EBP-2C] ; 将 当前数组首地址 赋值给ecx 0040D7A7 |. 8B51 0C MOV EDX,DWORD PTR DS:[ECX+C] ; ecx+C 相当于当前的地址加上0xC,可以理解为跳过两个int字节取下一组的第一个,也就是(*px)[1][1] 0040D7AA |. 52 PUSH EDX ; /<%d> 0040D7AB |. 68 1C204200 PUSH OFFSET my.??_C@_03HMFC@?$CFd?6?$AA@ ; |format = "%d " 0040D7B0 |. E8 FB38FFFF CALL my.printf ; \printf 0040D7B5 |. 83C4 08 ADD ESP,8 ; 堆栈平衡,下面就是准备输出代码中第二个printf了 0040D7B8 |. 8B45 D4 MOV EAX,DWORD PTR SS:[EBP-2C] ; 当前的数组的首地址赋值给eax 0040D7BB |. 83C0 10 ADD EAX,10 ; 现在是eax+10,相当于跳过两段,每段2个数,8字节,那就是跳过16字节 0040D7BE |. 8945 D4 MOV DWORD PTR SS:[EBP-2C],EAX ; 当前的eax地址赋值给ebp-2c指向的值 0040D7C1 |. 8B4D D4 MOV ECX,DWORD PTR SS:[EBP-2C] ; 取其中的值给ecx 0040D7C4 |. 8B51 0C MOV EDX,DWORD PTR DS:[ECX+C] ; ecx+C指向的值赋值给edx 0040D7C7 |. 52 PUSH EDX ; /<%d> 0040D7C8 |. 68 1C204200 PUSH OFFSET my.??_C@_03HMFC@?$CFd?6?$AA@ ; |format = "%d " 0040D7CD |. E8 DE38FFFF CALL my.printf ; \printf 0040D7D2 |. 83C4 08 ADD ESP,8 0040D7D5 |. 33C0 XOR EAX,EAX 0040D7D7 |. 5F POP EDI 0040D7D8 |. 5E POP ESI 0040D7D9 |. 5B POP EBX 0040D7DA |. 83C4 6C ADD ESP,6C 0040D7DD |. 3BEC CMP EBP,ESP 0040D7DF |. E8 4C39FFFF CALL my.__chkesp 0040D7E4 |. 8BE5 MOV ESP,EBP 0040D7E6 |. 5D POP EBP 0040D7E7 \. C3 RETN
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY