多维数组是连续固定大小的同类型数据块,指针是可变指向的地址变量;a3中a类型为int()[4],非int,sizeof(a)返回总字节,&a类型为int()3,传参必须指定第二维长度。

多维数组和指针在C语言中常被混用,但它们本质不同:多维数组是内存中一块连续、固定大小的同类型数据块;指针是存储地址的变量,可动态改变指向。理解这个根本差异,才能避免传参出错、越界访问或类型不匹配等问题。
多维数组名不是指针,而是数组类型的常量
例如 int a[3][4]; 中,a 的类型是 int (*)[4](指向含4个int的数组的指针),不是 int ** 或 int *。它代表整个二维结构的起始位置,不可赋值、不可自增。
-
sizeof(a)返回全部内存大小(如 3×4×sizeof(int) = 48 字节) -
&a类型为int (*)[3][4],即指向整个二维数组的指针 -
a + 1跳过一整行(16 字节),而&a + 1跳过整个二维数组(48 字节)
指针可以模拟多维数组,但类型必须严格匹配
要让指针正确遍历二维数组,必须声明为“指向数组的指针”,而非“指向指针的指针”。比如:
-
int (*p)[4] = a;✅ 合法,p指向第0行,p++移动到下一行 -
int *p = a[0];✅ 指向首行首元素,适合按一维方式遍历 -
int **p = a;❌ 编译错误,类型不兼容;a不是地址的地址
函数传参时,第二维长度不可省略
因为编译器需要知道每行占多少字节,才能正确计算 a[i][j] 的偏移地址。以下三种写法等价,都要求显式给出列数:
void func(int a[][4], int rows);-
void func(int a[3][4], int rows);(第一维长度被忽略) -
void func(int (*a)[4], int rows);(最清晰,强调指针语义)
数组与指针的退化只发生在特定上下文
数组名在绝大多数表达式中会自动转换为指向首元素的指针(如传参、加减运算),但有两个例外:
-
sizeof(数组名):得到整个数组大小,而非指针大小 -
&数组名:得到整个数组的地址,类型是“指向数组的指针”,不是“指向首元素的指针”
搞清这些区别,就不会把 int a[3][4] 当成 int ** 来用,也不会在函数里漏掉列维度。关键不在记语法,而在理解内存布局和类型系统如何协同工作。











