1.二维数组(父子数组)的父地址和子地址
1、知识点:
- 二维数组的本质还是一维数组,一维数组和二维数组的不同点是一维数组的元素是数值,二维数组(父数组)的元素是一个一维数组(子数组)。
- 我们有个统一的原则:数组名 == 地址常量。所以我们只要找到父数组名字和子数组名字,就能知道父数组地址和子数组地址。如图:
- 在上图中定义的二维数组a[3][4]中:
- a 是父数组名,是父地址(父数组的首地址)‘,又称为行地址。
- a[0]、a[1]、a[2]是三个子数组名,是子地址(子数组的首地址),又称为列地址。
2.父地址、子地址、数组元素到底是啥逻辑关系?
1、知识点:
- 由于数组名 == 地址常量,所以:父数组名+1表示:父地址偏移1个子数组占用的内存空间大小;子数组名+1表示:子地址偏移1个数组元素占用的内存空间大小。
- 二维数组在内存中是连续存储的,又根据数组名是常量没有常量地址的概念,将父数组名、子数组名、二维数组元素列出来,在内存中可能长这样:
3、通过二维数组的父子数组名偏移的方法间接访问二维数组中的每个元素(相当于一维数组中,用数组名偏移的方法间接访问数组元素)
1、方法一:
- 用子数组名 arr[i] 偏移 j 的方式间接访问二维数组的第i行第j列的元素:
第i行第j列元素的地址: arr[i]+j 第i行第j列元素的元素值: *(arr[i]+j)
- 举例:
#include <stdio.h> int main(int argc, char const *argv[]) { int arr[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}}; /* 笨方法 */ printf("address:%p,data:%d\n", arr[0]+0, *(arr[0]+0)); printf("address:%p,data:%d\n", arr[0]+1, *(arr[0]+1)); /* 子数组名加偏移的方法进行遍历 */ for(int i=0; i<3; i++){ for(int j=0; j<4; j++){ printf("address:%p,data:%d ", arr[i]+j, *(arr[i]+j)); } putchar('\n'); } return 0; }
2、方法二:
- 把子数组名 arr[i] 改成 父数组名 arr 偏移 i 取星花后, 再偏移 j 间接访问二维数组的第i行第j列的元素:
第i行第j列元素的地址: *(arr+i)+j 第i行第j列元素的元素值: *(*(arr+i)+j)
- 举例:
#include <stdio.h> int main(int argc, char const *argv[]) { int arr[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}}; for(int i=0; i<3; i++){ for(int j=0; j<4; j++){ printf("address:%p,data:%d ", *(arr+i)+j, *(*(arr+i)+j)); } putchar('\n'); } return 0; }
4.扫清认知盲区,别搞蒙圈了!
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
printf("add:%p\n", arr+1); //数值上等于&arr[1][0]
printf("add:%p\n", *(arr+1)); //数值上等于&arr[1][0]
return 0;
}
- 父数组名和子数组名:
- 逻辑上,*(a + i) 等价于 a[ i ]; *(a + i) + j 等价于 a[ i ] + j 。
- 地址上:a + i = *(a + i) = a[ i ] = &a[ i ][ 0 ]; *(a + i) + j = a[ i ] + j = &a[ i ][ j ]。
- 子数组名和数组元素:
- 逻辑上,*(a[ i ] + j) 等价于 a[ i ][ j ];
- 地址上: a[ i ] + j = &a[ i ][ j ];