此篇博客分为三个主题:
一、一维数组与指针
二、二维数组与指针
三、高维数组与指针
指针与数组密切相关,深刻理解二者关系不仅可以更加灵活运用数组,更可帮助深入理解指针。
一、一维数组与指针
我们首先来定义一个一位数组:
int arr[5] = {6,5,4,3,2,1};
在正式开始之前,先来明确两个定义:
1、首地址:数组首元素地址。也就是说,一维数组的为一个对应数据类型所占内存长度,二维数组的为一个一维数组(&arr[]),三维数组的为一个二维数组(&arr[][]),以此类推。
2、数组名是数组的首地址。
我们分别对arr、&arr[0]、&arr进行打印查看:
printf("%x\n",arr); //60fee4
printf("%x\n",&arr); //60fee4
printf("%x\n",&arr[0]); //60fee4
可以看到,在不对三者进行操作的情况下,三者指向的地址都为首元素地址。但是,如果对数组名进行操作之后三者还会是一样的吗?
printf("%x\n",arr+1); //60fee8
printf("%x\n",&arr+1); //60ff00
printf("%x\n",&arr[1]); //60fee8
如果对第二项算出的地址值与前面算出的地址值做差/sizeof(int), 你会发现长度刚好为数组的长度。所以我们可以得出以下结论:
1、&arr[0]即为arr,两者完全一样,其指针类型为int*,指向一个int内存单元。
2、&arr为数组指针,其指针类型为int(*)[7],指向一个完整的数组。
3、指针的加减以指针所指向的类型内存长度为单位进行偏移。
此外还要注意,数组名字与指针还有部分差别。数组名字不能自身进行++、--操作。为什么?原因就是只有arr指向的是首元素地址时,我们才可以从数组的第一个元素进行操作。假如第一次进行了++、--操作改变了arr自身的值,那么我们第二次使用这个数组的时候拿到的还是从第一个值开始的数组吗?所以说,严禁对数组名进行++、--操作!
除此之外,可以把数组名当成指针使用进行取值操作。下面的两种取值方法是等价的:
printf("%d\n",*(arr+1)); //5
printf("%d",arr[1]); //5
二、二维数组与指针
我们再将情况推广到二维数组。定义如下二维数组:
int arr[3][7] = {{6,5,4,3,2,1},{1,2,3,4,5,6},{4,5,6,7,8,9}};
还记得在上面我们讲的首地址的概念吗?所以,这里的二维数组的首元素为一维数组,所以arr指向的是第一个一维数组,类型为int(*)[7]。那么对于arr[0]来说,他又指向哪里呢(a[1]、a[2]同理)?
其实这里的arr[0]就是一维数组的数组名。为啥?扣首地址的定义。arr[0]代表的是一个一维数组,所以其指向的地址为a[0][0]的地址((*arr[0]) = a[0][0])。可以这么看,我们把arr[0]换为x,对于int x[7]来说,x便是x[0]的地址,即a[0][0]的地址。最后一点,&arr代表的什么呢?参照一维数组,这里&arr指向的是整个二维数组,类型为int(*)[3][7]。
根据上述描述可以推断出以下几种情况是等价的:
*(arr[0]+2) == arr[0][2];
*(*(arr+1)+2) == arr[1][2];
三、高维数组与指针
对于一个8维数组,我们应用“换元”的思想进行替换分析
int arr[2][3][4][5][6][7][8][9] = {...};
&arr ——> 8维
arr ——> 7维 ——> int(*)[ ][ ][ ][ ][ ][ ][ ]
arr[ ] ——> 6维 ——> int(*)[ ][ ][ ][ ][ ][ ] (将arr[ ]换元为x,7个括号少一个变为6维int x[ ][ ][ ][ ][ ][ ]。下方同理)
arr[ ][ ] ——> 5维 ——> int(*)[ ][ ][ ][ ][ ]
arr[ ][ ][ ] ——> 4维 ——> int(*)[ ][ ][ ][ ]
arr[ ][ ][ ][ ] ——> 3维 ——> int(*)[ ][ ][ ]
arr[ ][ ][ ][ ][ ] ——> 2维 ——> int(*)[ ][ ]
arr[ ][ ][ ][ ][ ][ ] ——> 1维 ——> int(*)[ ]
arr[ ][ ][ ][ ][ ][ ][ ] ——> 0维 ——> int*
arr[ ][ ][ ][ ][ ][ ][ ][ ] ——> 直接取值
推广到n维:
&arr ——> n维
arr ——> n-1维
arr[ ] ——> n-2维
arr[ ][ ] ——> n-3维
... ....
arr n-1个[ ] ——> 0维
arr n个[ ] ——> 直接取值