-
-
[原创]C语言-数组指针
-
发表于: 2023-5-5 23:01 6157
-
数组指针
指针数组和数组指针常常让人感到混淆。
从词性的角度理解。指针数组是指针修饰数组,强调的是数组。数组指针是数组修饰指针,强调的是指针。
从C语法定义来看:二者定义的语法不同。如果int (*p)[5] 不加括号,就变成了指针数组int *p[5]。
1 2 3 4 5 6 7 8 9 10 11 12 | int main() { int array[ 5 ] = { 1 , 2 , 3 , 4 , 5 }; int * arr[ 5 ]; / / 指针数组。数组arr中存储的都是 int 型的指针 int ( * p)[ 5 ]; / / 数组指针p。指针p指向一个长度为 5 个 int 的数组首地址 p = ( int ( * )[ 5 ])arr; / / 数组指针p指向arr的首地址 printf( "%d %d\n" , p, * p); return 0 ; } 输出: 11533108 11533108 |
从汇编代码看:注意默认是cdel调用约定,printf的参数是从右往左压栈。可以看到p和*p的值都是来自[ebp-44h]。因此对于cup而言,二者是没有区别的。
我认为p和*p是编译器用于某种区分的。
1 2 3 4 5 6 7 8 | printf( "%d %d\n" , p, * p); 006450D8 8B 45 BC mov eax,dword ptr [ebp - 44h ] 006450DB 50 push eax 006450DC 8B 4D BC mov ecx,dword ptr [ebp - 44h ] 006450DF 51 push ecx 006450E0 68 DC 7B 64 00 push 647BDCh 006450E5 E8 C7 C2 FF FF call 006413B1 006450EA 83 C4 0C add esp, 0Ch |
验证我的假设
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | int main() { int arr[ 5 ] = { 1 , 2 , 3 , 4 , 5 }; int ( * p)[ 2 ] = ( int ( * ) [ 2 ])arr; printf( "%d %d\n" , p, * p); printf( "%d %d %d\n" , p, p + 1 , * ( * (p + 1 ))); printf( "%d %d %d\n" , * p, ( * p) + 1 , * ((( * p) + 1 ) + 0 )); return 0 ; } 输出: 5241652 5241652 5241652 5241660 3 5241652 5241656 2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | printf( "%d %d %d\n" , p, p + 1 , * ( * (p + 1 ))); 00D450ED B8 04 00 00 00 mov eax, 4 00D450F2 6B C8 00 imul ecx,eax, 0 00D450F5 8B 55 D8 mov edx,dword ptr [ebp - 28h ] 00D450F8 8B 44 0A 08 mov eax,dword ptr [edx + ecx + 8 ] ; + 8 00D450FC 50 push eax 00D450FD 8B 4D D8 mov ecx,dword ptr [ebp - 28h ] 00D45100 83 C1 08 add ecx, 8 ; p + 1 - - > + 8 00D45103 51 push ecx 00D45104 8B 55 D8 mov edx,dword ptr [ebp - 28h ] 00D45107 52 push edx 00D45108 68 E4 7B D4 00 push 0D47BE4h 00D4510D E8 9F C2 FF FF call 00D413B1 00D45112 83 C4 10 add esp, 10h printf( "%d %d %d\n" , * p, ( * p) + 1 , * ((( * p) + 1 ) + 0 )); 00D45115 8B 45 D8 mov eax,dword ptr [ebp - 28h ] 00D45118 8B 48 04 mov ecx,dword ptr [eax + 4 ] ; + 4 00D4511B 51 push ecx 00D4511C 8B 55 D8 mov edx,dword ptr [ebp - 28h ] 00D4511F 83 C2 04 add edx, 4 ; ( * p) + 1 - - > + 4 00D45122 52 push edx 00D45123 8B 45 D8 mov eax,dword ptr [ebp - 28h ] 00D45126 50 push eax 00D45127 68 E4 7B D4 00 push 0D47BE4h 00D4512C E8 80 C2 FF FF call 00D413B1 00D45131 83 C4 10 add esp, 10h |
实验结果证明:
p和*p存储的值相等
p+1和*p+1的值不相等。
p+1:5241652 - 5241660 = 8 --> 2个int
*p+1:5241652 - 5241656 = 4 --> 1个int
证明p和*p的数据宽度不同。p是2个int宽度,*p是1个int宽度。表明:p指向的是arr首地址,是一个具有2个int宽度的数组的首地址。*p指向arr数组第一个元素的地址,其宽度是1个int宽度。
*(*(p+1))。p+1使得p向高地址移动1*2个int宽度。*(p+1)将移动宽度变为1个int宽度。*(*(p+1))取出指向地址的值:3。*(*(p+1)) == *(*(p+1)+0) == *(p+1)[0]
*(((*p)+1)+0)。*p将移动宽度变为1个int宽度。(*p)+1使得p向高地址移动1*1个int宽度。((*p)+1)+0使得p向高地址移动0*1个int宽度。*(((*p)+1)+0)取出指向地址的值:2。*(((*p)+1)+0) == *((*p)+1+0) == ((*p)+1)[0]
结论:
数组指针中,p和*p存储的值相等,是编译器用于区分不同数据宽度的一种标记方式。即p指向的是数组首地址,加减运算是按照数组宽度计算。*p指向数组的第一个元素的地址,加减运算是按照数组元素的宽度计算。
鄙人陋见,批评指正!
赞赏
- [原创]未导出函数PspTerminateProcess关闭360 5428
- [原创]超详细的3环和0环断链隐藏分析 13706
- [原创]2-9-9-12分页 4114
- [原创]底层分析C++虚函数、this、多态 10724
- [原创]逆向分析MmIsAddressValid函数2-9-9-12分页 2971