概要
指针数组
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一个数组首地址的时候 编译器是不会认为他是一个数组的, 想想也是 不然编译器怎么知道你是要单一的内存还是连续的空间呢.