跳到主要内容

指针与内存管理

指针是 C++ 直接操作内存的核心机制。掌握指针的语义,等价于掌握了堆内存与对象生命周期的控制权。智能指针与 RAII 才是现代 C++ 的首选,但理解原始指针仍有助于调试与读懂底层代码。

指针基础

指针是保存某个对象地址的变量。& 取地址,* 解引用。空指针用 nullptr(不要使用 NULL0)。指针本身也有类型,决定指针算术的步长。

int a = 42;
int* p = &a; // p 保存 a 的地址
int** pp = &p; // 指向指针的指针
*p = 100; // 通过指针修改 a

void* 是无类型指针,不能直接解引用,常用于 C 风格 API。const T* 表示指向常量的指针,T* const 表示指针本身是常量。

指针与数组

数组名在多数语境下会衰变为指向首元素的指针。指针算术按元素大小推进,而不是按字节推进。

int arr[5] = {1, 2, 3, 4, 5};
int* p = arr; // 等价于 &arr[0]
p[2] = 30; // 等价于 *(p + 2)

C++11 起的 std::arraystd::span 提供了带边界信息的数组抽象,优于裸数组。

动态内存

new 在堆上分配对象并返回指针,delete 释放。数组版本为 new[]delete[],两者必须配对。分配失败时 new 默认抛出 std::bad_alloc

int* buf = new int[n]; // 分配 n 个 int
for (int i = 0; i < n; ++i) buf[i] = i;
delete[] buf; // 配对释放,加 []

更推荐使用 std::vector<T> 替代手写动态数组;需要独占所有权时,使用 std::unique_ptr<T>,它会在析构时自动释放。

常见内存错误

  • 野指针:指针未初始化或指向已释放的内存,使用前应置 nullptr
  • 内存泄漏:new 后忘记 delete,或异常路径未释放。优先用智能指针。
  • 双重释放:同一块内存 delete 两次,会破坏堆结构。
  • 越界访问:数组下标越界,可能导致段错误或安全漏洞。

调试工具 AddressSanitizer(ASan)能在运行时检测这些错误,编译时加上 -fsanitize=address 即可启用。