Skip to content

数组与指针高频陷阱

核心结论

  • 数组名不是变量,不能自增;指针变量可以自增。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;   // ❌ 返回栈内存地址,调用者使用是未定义行为
}