对于数组而言,我们需要理解其数组的寻址公式,而其公式又与其内存的分布息息相关,所以当你了解了其内存分布,那么这个公式自然而然也能推出来。
首先数组有如下两点性质
连续性-排列连续
一致性-类型一致
因为有其连续的特点,所以其内存模型也就比较好理解,下面我们来看一下如下代码
int arr[5] = {0,1,2,3,4}
上面就是其内存模型,对于一致性的特点,可以推定其每个元素占用的空间大小一致,上面的话就是每个元素占4字节(int)
所以我们假设数组开始的首地址为0x10000,那么其各个元素在内存中占的地址是多少呢
arr[0] 0x10000
arr[1] 0x10004
arr[2] 0x10008
arr[3] 0x1000c
arr[4] 0x10010
其实很明显,上面就是一个等差数列,所以其一维数组的寻址公式为
ary+sizeof(type)*n
ary[3] -> 0x10000 + 4 * 3 = 0x1000C
此时就可以很方便的定位到每一个元素了。下面来看一下对应的一维数组的反汇编
int main(int argc, char* argv[])
{
int arr[5] = {1,2,3,4,5};
printf("%d",arr[2]);
printf("%d",arr[argc]);
printf("%d",arr[argc%7]);
for(int i=0;i < 5;++i)
{
printf("%d\r\n",arr[i]);
}
return 0;
}
对应的反汇编代码
21: int arr[5] = {1,2,3,4,5};
0040D7A8 C7 45 EC 01 00 00 00 mov dword ptr [ebp-14h],1 //说明数组首地址为ebp-0x14
0040D7AF C7 45 F0 02 00 00 00 mov dword ptr [ebp-10h],2
0040D7B6 C7 45 F4 03 00 00 00 mov dword ptr [ebp-0Ch],3
0040D7BD C7 45 F8 04 00 00 00 mov dword ptr [ebp-8],4
0040D7C4 C7 45 FC 05 00 00 00 mov dword ptr [ebp-4],5
22: printf("%d",arr[2]); //arr[2] -> ebp-14 + 4 * 2 = ebp-0c
0040D7CB 8B 45 F4 mov eax,dword ptr [ebp-0Ch]
0040D7CE 50 push eax
0040D7CF 68 1C 20 42 00 push offset string "%d" (0042201c)
0040D7D4 E8 27 39 FF FF call printf (00401100)
0040D7D9 83 C4 08 add esp,8
23: printf("%d",arr[argc]); // arr[argc] -> ebp-14h+argc*4
0040D7DC 8B 4D 08 mov ecx,dword ptr [ebp+8]
0040D7DF 8B 54 8D EC mov edx,dword ptr [ebp+ecx*4-14h] //换个写法 [ebp-14h+ecx*4]
0040D7E3 52 push edx
0040D7E4 68 1C 20 42 00 push offset string "%d" (0042201c)
0040D7E9 E8 12 39 FF FF call printf (00401100)
0040D7EE 83 C4 08 add esp,8
24: printf("%d",arr[argc%7]);
0040D7F1 8B 45 08 mov eax,dword ptr [ebp+8]
0040D7F4 99 cdq
0040D7F5 B9 07 00 00 00 mov ecx,7
0040D7FA F7 F9 idiv eax,ecx //先计算结果此时,结果在edx
0040D7FC 8B 54 95 EC mov edx,dword ptr [ebp+edx*4-14h] //寻址公式和上面相同
0040D800 52 push edx
0040D801 68 1C 20 42 00 push offset string "%d" (0042201c)
0040D806 E8 F5 38 FF FF call printf (00401100)
0040D80B 83 C4 08 add esp,8
25: for(int i=0;i < 5;++i)
0040D