数组与指针高频陷阱
核心结论
- 数组名不是变量,不能自增;指针变量可以自增。
int a[10]; int *p = a; ++p; // OK, ++a; // 不行
- 数组作函数参数会退化成指针,
sizeof(a) 在形参处仅得指针大小(64-bit 环境通常为 8 字节)。
- 二维数组传参必须给出列数:
void foo(int a[][4]); 行数可省略,编译器需列跨度做指针运算。
- 野指针:未初始化直接解引用;悬空指针:对象已释放/离开作用域后仍被使用。
- 指针加减按元素跨度移动:
p++ 让 p 前进 sizeof(*p) 字节。
- 多级指针解引用:
*pp == p,**pp 得到底层对象值。
- 返回局部变量地址属于未定义行为(栈内存已失效)。
示例代码
// 1) 数组名 vs 指针自增
int a[10];
int *p = a;
+p; // ✅ 合法,p 指向 a[1]
// ++a; // ❌ 编译错误:lvalue required
// 2) 形参数组退化为指针
void foo(int a[]) {
printf("%zu\n", sizeof(a)); // 输出 8(64-bit 指针大小)
}
// 3) 二维数组传参必须给出列数
void bar(int a[][4]); // ✅
// void bar(int a[][]); // ❌ 编译错误:必须指定列
// 4) 野指针/悬空指针
int *p_uninit; // 未初始化
// *p_uninit = 10; // ❌ 未定义行为,可能崩溃
int *q = malloc(sizeof(int));
free(q);
// *q = 10; // ❌ 悬空指针,未定义行为
// 5) 指针算术按元素跨度
int b[5] = {0};
int *r = b;
r++; // r 前进 sizeof(int)
printf("%p %p\n", (void*)b, (void*)r);
// 6) 多级指针
int x = 10; int *p1 = &x; int **pp = &p1;
printf("%d %d\n", *p1, **pp); // 10 10
// 7) 返回局部变量地址(示例说明问题)
int* bad() {
int t = 42;
return &t; // ❌ 返回栈内存地址,调用者使用是未定义行为
}