int arr[5]是5个int的数组,int (p)[5]是指向含5个int数组的指针;前者sizeof为5sizeof(int),后者为指针大小;传二维数组须用后者,解引用时(p)[i]合法而*p[i]越界。

int* arr[5] 和 int (*p)[5] 根本不是一回事
前者是「5个int*的数组」,后者是「指向含5个int的数组的指针」。编译器眼里类型完全不同,强行混用会直接报错,比如 cannot convert 'int*' to 'int (*)[5]'。关键区别不在语义绕口令,而在内存布局和 sizeof 行为:sizeof(arr) 返回 5 * sizeof(int*)(通常是 40 或 80 字节),而 sizeof(p) 返回指针大小(通常 8 字节)。传参时若想保留数组长度信息,必须用后者,前者一进函数就退化成 int**,长度丢失。
传二维数组给函数时,必须用 int (*p)[N]
常见错误是写成 void func(int* p, int rows, int cols) 或 void func(int p[][5]) —— 后者实际等价于 int (*p)[5],但很多人没意识到括号的强制绑定作用。正确做法是明确声明数组指针参数:void process(int (*mat)[5], int rows)。这样调用时可直接传 &arr[0] 或 arr(arr 是 int[3][5] 类型,自动转为 int (*)[5])。若漏掉括号写成 int* mat[5],函数拿到的只是 5 个独立指针,无法按行连续访问原始二维内存。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
*p[i] 和 (*p)[i] 解引用顺序完全不同
这是运行时最容易出错的地方,尤其在嵌套指针场景。假设 p 是 int (*)[4] 类型:
- (*p)[i]:先解引用 p 得到整个数组(即 int[4]),再取第 i 个元素;
- *p[i]:先算 p[i](相当于 *(p + i)),试图访问第 i 个「数组指针」——但 p 只是一个指针,p[i] 是越界读取,行为未定义。
列表对比:
-
int* arr[3]→*arr[1]合法,等价于*(arr[1]),取第二个指针所指的 int 值 -
int (*p)[3]→(*p)[1]合法,取 p 所指数组的第二个元素;*p[1]编译可能通过但运行崩溃 - 混淆常发生在把
int a[3]直接赋给int* p(合法) vsint (*p)[3](必须写&a)
用 cdecl.org 或 typedef 拆解复杂声明
遇到像 int *(*(*fp)(int))[10] 这种,别硬记。优先用 cdecl.org 粘贴进去,它会告诉你:“declare fp as pointer to function (int) returning pointer to array of 10 pointer to int”。更稳妥的是分步 typedef:typedef int* IntPtr;typedef IntPtr Arr10[10];typedef Arr10* FuncRet;FuncRet (*fp)(int);
这样每步类型清晰,也方便复用。所有声明最终都回归到「从变量名出发,按运算符优先级螺旋向右→左读」——但实际开发中,typedef 比死记规则可靠得多。
真正踩坑的点往往不在声明语法本身,而在传参时忘了加 &、解引用时搞错括号位置、或者误以为 sizeof 能在函数内拿到数组长度。类型系统不会替你记住这些。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










