正确做法是用 int (p)[5] = &arr 明确声明指向数组的指针,保留维度信息;int p = arr 仅得首元素地址,丢失长度且算术运算语义不同。

指针怎么存数组首地址?别用 int* p = arr 就完事
直接把数组名赋给指针,大多数时候能跑通,但容易掩盖类型信息丢失的问题。C++ 里数组名隐式转成指针,但原始维度和大小全丢了——sizeof(arr) 在函数内会变成指针大小,不是数组真实字节数。
- 正确做法是明确声明指向数组的指针,比如
int (*p)[5]表示“p 是指向含 5 个 int 的数组的指针” - 赋值必须严格匹配维度:
int arr[5] = {1,2,3,4,5}; int (*p)[5] = &arr;,注意是&arr,不是arr - 如果只写
int* p = arr;,你拿到的是首元素地址,但无法通过p推导出原数组长度,也不能做跨行指针运算(比如p + 1只跳 1 个 int,不是整块数组)
为什么 int* p = &arr[0] 和 int (*p)[5] = &arr 行为完全不同?
前者是“指向 int 的指针”,后者是“指向数组的指针”,底层地址值可能一样,但解引用和算术运算语义完全不同。
-
int* p = &arr[0]; printf("%d", *(p + 2));→ 输出arr[2],即第 3 个元素 -
int (*p)[5] = &arr; printf("%d", (*p)[2]);→ 同样输出arr[2],但*p是整个数组,再用[2]下标取值 -
int (*p)[5] = &arr; p++;→p指向内存中下一块 5-int 大小的区域,偏移量是5 * sizeof(int);而int* p自增只偏移sizeof(int)
传数组到函数时,指针类型选错会导致什么?
函数参数写成 void func(int* a) 看似通用,实则丢掉了数组长度信息,调用方必须额外传 size;而用数组引用或带维度的指针,编译器能做更多检查。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 推荐写法一(保留大小):
void func(int (&a)[5])—— 引用绑定,不能接受其他长度数组,编译期报错 - 推荐写法二(指针+长度):
void func(int (*a)[5], size_t n)—— 显式表明 a 指向的是 5 元素数组,n 控制循环次数 - 危险写法:
void func(int* a)+ 忘传 size → 越界读写静默发生,ASan 可能抓到,但不保证
动态分配二维数组时,int** 和 int (*)[N] 哪个更接近“真正二维”?
int** 是指针的指针,实际是“数组的数组”,每行内存不连续;int (*)[N] 才是连续内存块上真正的二维视图。
- 连续分配:
int (*p)[4] = new int[3][4];→ 分配 12 个 int 连续内存,p[1][2]直接算偏移 - 非连续分配:
int** p = new int*[3]; for(int i=0; i → 每行 new 单独堆块,缓存不友好,释放要两层 delete - 注意:
new int[3][4]返回类型就是int (*)[4],不能直接赋给int**,编译失败
数组地址不是单纯“一个数字”,它附带维度契约。用错指针类型,编译器不会拦你,但越界、误算、释放泄漏全在运行时等你。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










