数组名不是指针,而是类型为int[5]的地址常量,仅在多数表达式中隐式转换为int*;sizeof(arr)在定义处返回20,在函数内返回8,因传参时数组退化为指针。

数组名不是指针,但会隐式转成指针
很多人一上来就写 int* p = arr; 觉得“数组就是指针”,其实错了。数组名 arr 是一个地址常量,类型是 int[5](假设长度为5),而 int* 是指向单个 int 的指针。编译器在多数表达式中(比如传参、加减运算)会把 arr 隐式转换成指向首元素的 int*,但这不等于它“是”指针。
典型错误现象:sizeof(arr) 在函数内返回 8(指针大小),而在定义处返回 20(5×4),就是因为传参时数组退化成了指针。
- 定义数组时:用
int arr[5] = {1,2,3,4,5};,sizeof(arr)是总字节数 - 传给函数时:形参写
void f(int arr[])或void f(int* arr)效果一样,都收不到长度信息 - 想保留长度?必须额外传
size_t n,或用std::array/std::vector
用指针遍历数组时,别越界还假装安全
指针算术依赖类型,p + i 实际偏移是 i * sizeof(*p)。看似方便,但编译器不检查边界,p[100] 可能读到栈上别的变量,甚至段错误。
常见错误现象:循环写成 for (int i = 0; p[i] != 0; ++i),但数组里根本没有 0 值,直接越界;或者用 判定末尾,多走一次。
- 安全做法:明确知道长度,用
for (int i = 0; i 配合 <code>p[i] - 用指针迭代:写
for (int* q = p; q != p + n; ++q),别用 -
std::end(arr)对原生数组有效(C++17 起),但仅限定义作用域内,函数参数里失效
new int[n] 返回的是指针,不是数组类型
int* p = new int[5]; 分配的是堆上连续内存,但 p 就是纯 int*,没有长度信息,也没有 sizeof 可靠值。它和栈数组行为差异很大。
典型错误现象:对 p 调用 delete[] 忘了方括号 → 未定义行为;或误以为 p + 1 和栈数组一样“天然安全”——其实堆上越界更难调试。
- 必须配对使用
delete[] p;,不能用delete p; - 别依赖
p推导长度,自己存size_t len = 5; - 现代 C++ 优先用
std::vector<int></int>,它自带长度、自动管理内存、支持范围 for
char 数组和字符串字面量混用最易崩
char s[] = "hello"; 是可修改的栈数组;char* p = "hello"; 指向只读内存,改 p[0] = 'H' 直接 crash。
常见错误现象:函数返回局部 char[] 地址,调用方拿到野指针;或把字符串字面量赋给非 const char*,编译器可能不报错(C++11 后已要求 const)。
- 写字符串字面量:声明用
const char* p = "hello"; - 要修改内容:用
char buf[100]; strcpy(buf, "hello");或std::string s = "hello"; - 函数返回字符串:返回
std::string,或确保返回的是静态存储期数据(如static char buf[...];),别返栈数组地址
最难绷的是:同一段代码,在栈上跑得欢,在函数里传参后行为突变——本质都是类型退化和生命周期没理清。盯住 sizeof、typeid 和内存归属,比背口诀管用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











