逆向学习 指针数组与数组指针

概要

指针数组

Array of pointers
和char a[10], short b[10], int c[10]一样, 指针数组就是数组, 不过是里面存放的类型是指针

数组指针

A pointer to an array
和char* a, short* b, int* c一样, 一个指向数组的指针

int(*arr)[10]代表arr指向一个有10个存储空间的数组的地址

分析

正向代码
#include "iostream"

void printArr(int* arr,int length)
{
	for (int i = 0; i < length; i++)
		printf("%d  ", *(arr + i));
	puts("");
}

int main(void)
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 10,9,8,7,6,5,4,3,2,1 };
	
	//int* p = arr2;
	//printf("%d  %d\n", sizeof(arr2), sizeof(p));	虽然p也是数组首地址和arr2相同作用 但是编译器只是把它当成一块普通的内存

	int* pArr[2] = { arr1,arr2 };
	printf("%d\n", *(*(pArr + 0) + 2));	//3
	printArr(*(pArr + 1), 10);

	int(*arrP1)[10] = (int(*)[10])arr2;
	printf("%d\n", *(*arrP1 + 3));	//7
	printArr(*arrP1, sizeof(*arrP1) / 4);

	int(*arrP2)[2] = (int(*)[2])arr2;
	printf("%d\n", *(*(arrP2 + 2) + 3));	//3
	printArr(*arrP2, sizeof(*arrP2) / 4);	//这里就体现了数组指针的差别, 虽然和p一样都表示数组首地址, 但编译器把它当做数组

	return 0;
}
指针数组
反汇编
	int* pArr[2] = { arr1,arr2 };
0027518E  lea         eax,[ebp-30h]  
00275191  mov         dword ptr [ebp-70h],eax  
00275194  lea         eax,[ebp-60h]  
00275197  mov         dword ptr [ebp-6Ch],eax  
//int* pArr[2]代表 pArr存放了 2个指针类型数据 (arr1和 arr2的首地址)的数组

	printf("%d\n", *(*(pArr + 0) + 2));	//3
0027519A  mov         eax,dword ptr [ebp-70h]  
0027519D  mov         ecx,dword ptr [eax+8]  
//*(pArr+0)代表 MOV EAX,DOWRD PTR [EBP-70H]即第一个数组 arr1
//*(arr1+2)即找 arr1的第三个值
002751A0  push        ecx  
002751A1  push        277BE8h  
002751A6  call        0027104B  
002751AB  add         esp,8  

数组指针
反汇编

一个普通的指针 这个指针指向一个数组的首地址

	int(*arrP1)[10] = (int(*)[10])arr2;
002751BC  lea         eax,[ebp-60h]  
002751BF  mov         dword ptr [ebp-7Ch],eax  
//可以看到 在反汇编中 形式上没有任何差别

	printf("%d\n", *(*arrP1 + 3));	//7
002751C2  mov         eax,dword ptr [ebp-7Ch]  
002751C5  mov         ecx,dword ptr [eax+0Ch]
//[ebp-7ch]中存储 arr2的地址	arrP1
//[[ebp-7CH]]就是 arr2首地址中的值即 arr2[0]  **arrP1
//所以 *(*arrP1 + 3)== arr[3]
002751C8  push        ecx  
002751C9  push        277BE8h  
002751CE  call        0027104B  
002751D3  add         esp,8  


	int(*arrP2)[2] = (int(*)[2])arr2;
002751E4  lea         eax,[ebp-60h]  
002751E7  mov         dword ptr [ebp+FFFFFF78h],eax 
//从正向代码比较难理解这样的做法,其实和 (*)[10]一样 只不过是一个 40字节数组只取 8字节分成 5个
//然后用一个指针指向它
//所以下面的 +2就代表 arr2中的第三个 8字节 +3就代表 8字节数组的第 4个(正向上实际只有2个)
	printf("%d\n", *(*(arrP2 + 2) + 3));	//3
002751ED  mov         eax,dword ptr [ebp+FFFFFF78h]  
002751F3  mov         ecx,dword ptr [eax+1Ch]  
002751F6  push        ecx  
002751F7  push        277BE8h  
002751FC  call        0027104B  
00275201  add         esp,8  
总结

第一次看到数组指针的时候直接蒙了, 但是自己弄下来发现其实它就是个指针, 写法上让我产生了困惑.
而指针数组也不难理解, 和其他任何形式的数组一样, 只是一个用来存储指针的数组

有一个额外的发现是sizeof一个数组首地址的时候 编译器是不会认为他是一个数组的, 想想也是 不然编译器怎么知道你是要单一的内存还是连续的空间呢.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

四位

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值