野指针是未初始化的指针,值为随机地址;悬挂指针是曾有效但所指内存已被释放而未置空的指针,二者成因、调试特征及修复方式均不同,不可混为一谈。

野指针是未初始化的指针,值为随机地址
野指针最典型的表现就是声明后直接使用:int* p; 然后立刻 *p = 42;。此时 p 的值来自栈上未初始化的内存,可能是 0x7fffa1b2c3d8 这类毫无规律的数字,不是 nullptr,也不是已知堆地址。它根本没被赋予合法目标,所以解引用会随机崩在任意位置。
常见错误场景包括:
- 局部指针变量声明不初始化就传参或解引用
-
new失败但没检查返回值(C++ 默认抛异常,但加了std::nothrow后可能返回nullptr,若忽略该检查而直接用,p就成了野指针) - 结构体/类中指针成员未在构造函数里初始化
悬空指针是曾有效、后被释放却未置空的指针
悬空指针的危险在于“看起来合理”:它的地址可能是之前 new 或 malloc 返回的,甚至还能读写几轮——因为那块内存还没被覆盖或重分配。结果 bug 延迟暴露,崩溃点和问题根源相隔很远。
典型来源有:
-
delete p;或free(p);后没写p = nullptr; - 两个指针指向同一块堆内存,只对其中一个
delete,另一个仍保留旧地址 - 函数返回局部变量地址:
int* f() { int x = 42; return &x; }—— 返回值是悬空指针,不是野指针 -
std::vector::resize()或clear()导致原有迭代器/裸指针失效,继续使用即悬空
为什么不能统一叫“野指针”?
虽然两者都导致未定义行为,但调试线索和修复方式完全不同:
- 野指针的地址通常杂乱无章,AddressSanitizer 一般报
heap-buffer-overflow或直接段错误,无上下文; - 悬空指针的地址往往是“熟面孔”,ASan 会明确提示
heap-use-after-free,并指出哪次free或delete是源头; - 野指针靠初始化预防(
int* p = nullptr;),悬空指针靠释放后置空 + 避免多指针共享同一块内存; - 智能指针如
std::unique_ptr能天然消灭悬空指针,但对野指针无效——你依然可以声明std::unique_ptr<int> p;</int>后不赋值就解引用(编译不过,但裸指针能过)。
最容易被忽略的细节
野指针和悬空指针都不会自动清零,也不会触发编译警告。它们在 Release 模式下更难复现,在 ASan 关闭时可能“偶然正常”。真正棘手的是:悬空指针常伴随多线程环境——一个线程刚 delete,另一个线程正用着 p,这时连 ASan 都可能漏检。别依赖“它没崩就代表没问题”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











