|
楼主 |
发表于 2020-3-3 10:00:57
|
显示全部楼层
本帖最后由 DL_one 于 2020-3-3 10:06 编辑
数组学习
0x01 初始化数组1、没有初始化数组 - #include "stdio.h"
- int main(void)
- {
- int data[4];
- for (int i=0;i<4;i++)
- {
- printf("%d\t",data[i]);
- }
-
- return 0;
- }
复制代码反汇编: - 4: int data[4];
- 5: for (int i=0;i<4;i++)
- 00401028 C7 45 EC 00 00 00 00 mov dword ptr [ebp-14h],0
- 0040102F EB 09 jmp main+2Ah (0040103a)
- 00401031 8B 45 EC mov eax,dword ptr [ebp-14h]
- 00401034 83 C0 01 add eax,1
- 00401037 89 45 EC mov dword ptr [ebp-14h],eax
- 0040103A 83 7D EC 04 cmp dword ptr [ebp-14h],4
- 0040103E 7D 17 jge main+47h (00401057)
- 6: {
- 7: printf("%d\t",data[i]);
- 00401040 8B 4D EC mov ecx,dword ptr [ebp-14h]
- 00401043 8B 54 8D F0 mov edx,dword ptr [ebp+ecx*4-10h]
- 00401047 52 push edx
- 00401048 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040104D E8 3E 00 00 00 call printf (00401090)
- 00401052 83 C4 08 add esp,8
- 8: }
- 00401055 EB DA jmp main+21h (00401031)
- 9:
- 10: return 0;
- 00401057 33 C0 xor eax,eax
- 11: }
复制代码我们可以看到int data[4];没有生成机器码,说明cpu到这里不会干任何事情。从上面的输出结果可以得出,定义一个数组,会给这个数组分配内存空间,如果没有初始化,数组的内容是相应分配空间的内容,这里我们称之为垃圾值 2、部分初始化 - #include "stdio.h"
- int main(void)
- {
- int data[4]={1,2};
- for (int i=0;i<4;i++)
- {
- printf("%d\t",data[i]);
- }
-
- return 0;
- }
复制代码反汇编: - 4: int data[4]={1,2};
- 00401028 C7 45 F0 01 00 00 00 mov dword ptr [ebp-10h],1
- 0040102F C7 45 F4 02 00 00 00 mov dword ptr [ebp-0Ch],2
- 00401036 33 C0 xor eax,eax
- 00401038 89 45 F8 mov dword ptr [ebp-8],eax
- 0040103B 89 45 FC mov dword ptr [ebp-4],eax
- 5: for (int i=0;i<4;i++)
- 0040103E C7 45 EC 00 00 00 00 mov dword ptr [ebp-14h],0
- 00401045 EB 09 jmp main+40h (00401050)
- 00401047 8B 4D EC mov ecx,dword ptr [ebp-14h]
- 0040104A 83 C1 01 add ecx,1
- 0040104D 89 4D EC mov dword ptr [ebp-14h],ecx
- 00401050 83 7D EC 04 cmp dword ptr [ebp-14h],4
- 00401054 7D 17 jge main+5Dh (0040106d)
- 6: {
- 7: printf("%d\t",data[i]);
- 00401056 8B 55 EC mov edx,dword ptr [ebp-14h]
- 00401059 8B 44 95 F0 mov eax,dword ptr [ebp+edx*4-10h]
- 0040105D 50 push eax
- 0040105E 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 00401063 E8 28 00 00 00 call printf (00401090)
- 00401068 83 C4 08 add esp,8
- 8: }
- 0040106B EB DA jmp main+37h (00401047)
- 9:
- 10: return 0;
- 0040106D 33 C0 xor eax,eax
- 11: }
复制代码从下面这段代码可以看出,部分初始化,编译器会给数组分配连续的空间,将有值的部分赋值到相应的内存,没有初始化的,复制为0,这就是为什么上面的输出结果为什么后面没有赋值的是0 - 4: int data[4]={1,2};
- 00401028 C7 45 F0 01 00 00 00 mov dword ptr [ebp-10h],1
- 0040102F C7 45 F4 02 00 00 00 mov dword ptr [ebp-0Ch],2
- 00401036 33 C0 xor eax,eax
- 00401038 89 45 F8 mov dword ptr [ebp-8],eax
- 0040103B 89 45 FC mov dword ptr [ebp-4],eax
复制代码3、全部初始化数组 - #include "stdio.h"
- int main(void)
- {
- int data[4]={1,2,3,4};
- for (int i=0;i<4;i++)
- {
- printf("%d\t",data[i]);
- }
-
- return 0;
- }
复制代码- 4: int data[4]={1,2,3,4};
- 00401028 C7 45 F0 01 00 00 00 mov dword ptr [ebp-10h],1
- 0040102F C7 45 F4 02 00 00 00 mov dword ptr [ebp-0Ch],2
- 00401036 C7 45 F8 03 00 00 00 mov dword ptr [ebp-8],3
- 0040103D C7 45 FC 04 00 00 00 mov dword ptr [ebp-4],4
- 5: for (int i=0;i<4;i++)
- 00401044 C7 45 EC 00 00 00 00 mov dword ptr [ebp-14h],0
- 0040104B EB 09 jmp main+46h (00401056)
- 0040104D 8B 45 EC mov eax,dword ptr [ebp-14h]
- 00401050 83 C0 01 add eax,1
- 00401053 89 45 EC mov dword ptr [ebp-14h],eax
- 00401056 83 7D EC 04 cmp dword ptr [ebp-14h],4
- 0040105A 7D 17 jge main+63h (00401073)
- 6: {
- 7: printf("%d\t",data[i]);
- 0040105C 8B 4D EC mov ecx,dword ptr [ebp-14h]
- 0040105F 8B 54 8D F0 mov edx,dword ptr [ebp+ecx*4-10h]
- 00401063 52 push edx
- 00401064 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 00401069 E8 22 00 00 00 call printf (00401090)
- 0040106E 83 C4 08 add esp,8
- 8: }
- 00401071 EB DA jmp main+3Dh (0040104d)
- 9:
- 10: return 0;
- 00401073 33 C0 xor eax,eax
复制代码可以看出如果一开始全部初始化数组,会立即分配连续空间给数组,每个空间赋值为数组相应位置的值 4、总结 不初始化数组,数组元素存储的是垃圾值;部分初始化数组,剩余的被初始化为0;全部初始化,将值赋值到相应内存空间,而且数组的物理地址连续 0x02多维数组是如何分配空间的 多维数组的初始化情况和一维数组一样,那么多维数组是如何分配空间的呢?我们以二维数组为列: - #include "stdio.h"
- int main(void)
- {
- int data[2][2]={{1,2},{3,4}};
-
- return 0;
- }
复制代码反汇编: - 4: int data[2][2]={{1,2},{3,4}};
- 00401028 C7 45 F0 01 00 00 00 mov dword ptr [ebp-10h],1
- 0040102F C7 45 F4 02 00 00 00 mov dword ptr [ebp-0Ch],2
- 00401036 C7 45 F8 03 00 00 00 mov dword ptr [ebp-8],3
- 0040103D C7 45 FC 04 00 00 00 mov dword ptr [ebp-4],4
- 5:
- 6: return 0;
- 00401044 33 C0 xor eax,eax
- 7: }
复制代码我们可以看出先将1,2存到连续空间。再将3,4存到接下来的空间(数组的内存空间是连续的),所以这就是为什么上课时老师说把二维数组当成一维数组来理解了,data[0]和data[1]分别为一个一维数组,二维数组按照从左到右,从上到下存储,地址连续
int data[2][2]:data是一个两个元素的数组,每个元素内含2个int类型元素的数组 data的首地址是data[0],data[0]是一个内含2个int类型值的数组,所以data[1]也是这样 0x03 指针和数组1、一维数组
我们知道数组名是数组的首地址,可为什么呢?接下来我们分析 - #include "stdio.h"
- int main(void)
- {
- int data[4]={1,3,7,4};
- int *p;
- p=data;
- printf("%d\n",p[0]);
- printf("%d\n",*p+2);
- printf("%d\n",*(p+2));
- return 0;
- }
复制代码反汇编: - 4: int data[4]={1,3,7,4};
- 0040D738 C7 45 F0 01 00 00 00 mov dword ptr [ebp-10h],1
- 0040D73F C7 45 F4 03 00 00 00 mov dword ptr [ebp-0Ch],3
- 0040D746 C7 45 F8 07 00 00 00 mov dword ptr [ebp-8],7
- 0040D74D C7 45 FC 04 00 00 00 mov dword ptr [ebp-4],4
- 5: int *p;
- 6: p=data;
- 0040D754 8D 45 F0 lea eax,[ebp-10h]
- 0040D757 89 45 EC mov dword ptr [ebp-14h],eax
- 7: printf("%d\n",p[0]);
- 0040D75A 8B 4D EC mov ecx,dword ptr [ebp-14h]
- 0040D75D 8B 11 mov edx,dword ptr [ecx]
- 0040D75F 52 push edx
- 0040D760 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D765 E8 26 39 FF FF call printf (00401090)
- 0040D76A 83 C4 08 add esp,8
- 8: printf("%d\n",*p+2);
- 0040D76D 8B 45 EC mov eax,dword ptr [ebp-14h]
- 0040D770 8B 08 mov ecx,dword ptr [eax]
- 0040D772 83 C1 02 add ecx,2
- 0040D775 51 push ecx
- 0040D776 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D77B E8 10 39 FF FF call printf (00401090)
- 0040D780 83 C4 08 add esp,8
- 9: printf("%d\n",*(p+2));
- 0040D783 8B 55 EC mov edx,dword ptr [ebp-14h]
- 0040D786 8B 42 08 mov eax,dword ptr [edx+8]
- 0040D789 50 push eax
- 0040D78A 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D78F E8 FC 38 FF FF call printf (00401090)
- 0040D794 83 C4 08 add esp,8
- 10: return 0;
- 0040D797 33 C0 xor eax,eax
复制代码从数组初始化我们看不出来data是数组的首地址吗,但可以从p=data看出 - 6: p=data;
- 0040D754 8D 45 F0 lea eax,[ebp-10h]
- 0040D757 89 45 EC mov dword ptr [ebp-14h],eax
复制代码把 [ebp-10h]偏移地址给eax,eax再赋值给dword ptr [ebp-14h],ebp-10h是第一个元素1的地址,所以data是数组首地址,我们将data值赋值给p,此时p和data可以看成等同的,p[0]就是data[0]。
指针加1是增加一个存储单元,比如说*(p+2),p+2就是增加两个存储单元(int是4byte),所以输出*(p+2)是7 输出p+2,此时p是1,加2是3所以会输出3 2、多维数组 以二维数组为例 - #include "stdio.h"
- int main(void)
- {
- int data[3][3]={{1,2,3},{4,5,6},{7,8,9}};
- int (* p)[3]; //指向一个含有3个int类型的数组
- p=data;
- printf("%d\n",p);
- printf("%d\n",*p);
- printf("%d\n",*(p+1));
- printf("%d\n",**p);
- printf("%d\n",p[0]);
- printf("%d\n",*p[0]);
- return 0;
- }
复制代码反汇编: - 4: int data[3][3]={{1,2,3},{4,5,6},{7,8,9}};
- 0040D738 C7 45 DC 01 00 00 00 mov dword ptr [ebp-24h],1
- 0040D73F C7 45 E0 02 00 00 00 mov dword ptr [ebp-20h],2
- 0040D746 C7 45 E4 03 00 00 00 mov dword ptr [ebp-1Ch],3
- 0040D74D C7 45 E8 04 00 00 00 mov dword ptr [ebp-18h],4
- 0040D754 C7 45 EC 05 00 00 00 mov dword ptr [ebp-14h],5
- 0040D75B C7 45 F0 06 00 00 00 mov dword ptr [ebp-10h],6
- 0040D762 C7 45 F4 07 00 00 00 mov dword ptr [ebp-0Ch],7
- 0040D769 C7 45 F8 08 00 00 00 mov dword ptr [ebp-8],8
- 0040D770 C7 45 FC 09 00 00 00 mov dword ptr [ebp-4],9
- 5: int (* p)[3];
- 6: p=data;
- 0040D777 8D 45 DC lea eax,[ebp-24h]
- 0040D77A 89 45 D8 mov dword ptr [ebp-28h],eax
- 7: printf("%d\n",p);
- 0040D77D 8B 4D D8 mov ecx,dword ptr [ebp-28h]
- 0040D780 51 push ecx
- 0040D781 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D786 E8 05 39 FF FF call printf (00401090)
- 0040D78B 83 C4 08 add esp,8
- 8: printf("%d\n",*p);
- 0040D78E 8B 55 D8 mov edx,dword ptr [ebp-28h]
- 0040D791 52 push edx
- 0040D792 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D797 E8 F4 38 FF FF call printf (00401090)
- 0040D79C 83 C4 08 add esp,8
- 9: printf("%d\n",*(p+1));
- 0040D79F 8B 45 D8 mov eax,dword ptr [ebp-28h]
- 0040D7A2 83 C0 0C add eax,0Ch
- 0040D7A5 50 push eax
- 0040D7A6 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D7AB E8 E0 38 FF FF call printf (00401090)
- 0040D7B0 83 C4 08 add esp,8
- 10: printf("%d\n",**p);
- 0040D7B3 8B 4D D8 mov ecx,dword ptr [ebp-28h]
- 0040D7B6 8B 11 mov edx,dword ptr [ecx]
- 0040D7B8 52 push edx
- 0040D7B9 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D7BE E8 CD 38 FF FF call printf (00401090)
- 0040D7C3 83 C4 08 add esp,8
- 11: printf("%d\n",p[0]);
- 0040D7C6 8B 45 D8 mov eax,dword ptr [ebp-28h]
- 0040D7C9 50 push eax
- 0040D7CA 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D7CF E8 BC 38 FF FF call printf (00401090)
- 0040D7D4 83 C4 08 add esp,8
- 12: printf("%d\n",*p[0]);
- 0040D7D7 8B 4D D8 mov ecx,dword ptr [ebp-28h]
- 0040D7DA 8B 11 mov edx,dword ptr [ecx]
- 0040D7DC 52 push edx
- 0040D7DD 68 1C 20 42 00 push offset string "%d\t" (0042201c)
- 0040D7E2 E8 A9 38 FF FF call printf (00401090)
- 0040D7E7 83 C4 08 add esp,8
- 13: return 0;
- 0040D7EA 33 C0 xor eax,eax
复制代码从p=data;, printf("%d\n",p[0]);,printf("%d\n",**p);的反汇编看出,数组名和数组名[0]是首元素的地址,printf("%d\n",*p);,数组名像是指向数组名[0]的指针,这就是为什么二维数组的元素可以看成一维数组 printf("%d\n",*(p+1));从反汇编里看出,加了0ch,就是加12,并不是加4,二维数组的元素是一维数组,一维数组占3个int类型,所以12,所以*(p+1)指向data[1] 函数里使用二维数组:比如说int sum(int data[][3]),第一个[]表明data是一个指针
|
|