C语言所谓的二维数组只是一个逻辑概念,物理存储仍然是一维的、线性的、顺序存储的。
逻辑二维数组方便相关指针按行或按列移动,内部指针的算术运算由编译器完成。
C语言的数组名是一种特殊的存在,它的本质是一个具有常量性质的指针,它的地址是其存储单元的首地址,用于指针偏移(指针移动或指针算术运算)的基地址,在不同的 中上下文中,数组名称具有不同的类型信息,这会影响它们的算术运算。
1 与运算符和&一起使用时,表示整个数组空间
int arr[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
int size = sizeof arr / sizeof *arr; // 在该上下文中,arr是数组的地址,其类型是int(*)[3][4]
funcD3(&arr,3,4); // 在该上下文中,arr是数组的地址,其类型是int(*)[3][4]
2.表示第0个元素的地址(数组第一个元素的地址)
funcD2(arr,3,4); // 在该上下文中,arr是数组首元素的地址,其类型是int(*)[4]
*(*(arr+i)+j):第i行第j列的空间
*(*(arr+i)+j) ——> *(arr[i]+j) ——> arr[i][j]
这些写法都是有效的,(*(arr+i))[j]的写法也是正确的。
我们知道,要分析一个指针,就要分析指针本身的类型和指针目标的类型。 一个指针和一个整型常量的加减法,比如arr+i,代表指针移动,结果还是同类型的指针。 我们知道表达式操作需要相同的类型,否则就需要隐式或显式类型转换。 arr是一个指针,有类型的指针,指针是一个地址,一个整型值,arr的目标类型是int[4],这就决定了它移动的时候移动的字节数就是它的目标类型的长度,所以达到一个共识。 *(arr+i) 仍然是一个指针,它自己的类型是int*,目标类型是int(目标类型是指它指向的类型或者它解引用的类型)。
假设有一个数组int arr[R][C],可以通过指针变量int*p访问,一维数组指针int(*ap)[C],二维数组指针int(*arr)[ R][C] ,下面是演示代码,从中也可以看出二维数组名与这些变量的赋值关系:
#include
void funcD1(int *p,int r,int c)
{
for(int i=0;i