数组名不是指针,但多数表达式中会退化为int;不能赋值或自增;传参时int[]与int等价,引用形参void f(int(&a)[5])可保留长度;sizeof仅在定义域有效;初始化推荐= {…}更兼容;越界访问无编译错误但行为未定义,建议用-sanitize=address检测或改用std::array/vector。

数组名不是指针,但用法容易混淆
定义 int arr[5] 后,arr 在多数表达式中会“退化”为指向首元素的指针(类型是 int*),但它本身不是指针变量——没有独立存储空间,不能赋值、不能自增。常见错误是写 arr++ 或 arr = &x,编译直接报错:lvalue required as increment operand 或 assignment to array type。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 需要移动访问时,用下标
i或另建指针变量:int* p = arr;再操作p++ - 传参给函数时,形参写成
int arr[]或int* arr效果一样,但前者更体现语义;若想禁用退化、保留长度信息,改用引用:void f(int (&a)[5]) - 用
sizeof(arr)获取总字节数只在定义作用域内有效;一旦传入函数,sizeof(arr)就变成指针大小(通常是 8)
初始化时大括号和等号的细节差别
写 int a[3] = {1, 2}; 和 int a[3]{1, 2}; 行为一致(剩余元素零初始化),但去掉等号后加括号(即“直接列表初始化”)会触发更严格的检查:C++11 起,int a[3]{1, 2, 3, 4}; 编译失败,而带等号的版本在某些旧编译器里可能只警告。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 显式初始化全部元素用
= {…}更兼容;追求现代风格且确定长度匹配,可用{…}(无等号) - 留空初始化(如
int a[5]{};)会将所有元素设为 0;但int a[5];(无任何初始化)内容是未定义的,别假设它是零 - 字符数组例外:
char s[] = "abc";自动算长度为 4(含\0),而char s[3] = "abc";是错误的——越界,编译器通常报initializer-string for char array is too long
越界访问不报错,但行为完全不可预测
C++ 对数组不做运行时边界检查。写 arr[100](实际只有 5 个元素)不会崩溃,也不会报错,可能读到栈上其他变量、返回垃圾值、偶然正常、或引发后续段错误——取决于内存布局和优化级别。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 调试阶段开启编译器检查:Clang/GCC 加
-fsanitize=address,运行时能捕获越界并打印详细位置 - 生产环境别依赖
operator[]的“宽容”,该用std::array或std::vector时就用——它们的at()成员函数会抛std::out_of_range - 循环下标务必检查:
for (int i = 0; i 中 <code>N必须是真实长度,别硬写数字或用sizeof(arr)/sizeof(arr[0])后又把数组传进函数里去算
静态存储期数组的零初始化规则
全局或 static 局部数组(如 static int buf[1024];)即使不写初始化器,也会被自动清零;但普通局部数组(int buf[1024];)不会。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 别靠“好像没初始化也跑得通”来省事——未初始化的栈数组内容是上次栈帧残留,不同运行结果可能完全不同
- 如果逻辑上必须全零,显式写
= {}或= {0},既清晰又跨平台;= {0}会让第一个元素为 0,其余隐式零初始化,效果同= {} - 注意:
const int a[3];不允许无初始化器,必须写const int a[3] = {0};或类似形式,否则编译失败
数组长度必须是编译期常量,连 const int n = 5; int a[n]; 在标准 C++ 里也是非法的(GCC 支持是扩展)。真要动态大小,绕不开 std::vector。










