free(): invalid pointer 错误本质是向free()传入了非法指针,即非malloc/calloc/realloc返回的原始地址,如栈内存、已释放区域、字符串字面量或指针算术偏移后的地址。

free(): invalid pointer 错误本质是什么
这个报错不是数组越界本身触发的,而是后续 free()(或 delete)时检测到指针地址非法——比如指向栈内存、已释放区域、未对齐地址,或根本不是 malloc()/new 返回的原始地址。C++ 中若用 new[] 分配数组却用 delete(非 delete[])释放,也可能导致堆元数据损坏,最终在下一次 free() 时暴露。
它往往滞后出现:出问题的代码可能在几十行之前,而崩溃点只是“压垮骆驼的最后一根稻草”。
检查 malloc/new 和 free/delete 是否严格配对
这是最常见原因,尤其混用 C/C++ 内存管理接口时:
- 用
malloc()或calloc()分配,必须用free();用new或new[]分配,必须用delete或delete[]—— 不能交叉 -
new[]分配的数组,必须用delete[],否则析构函数只调用一次,且堆头信息可能被破坏 - 检查是否对局部数组(如
int arr[10];)或字符串字面量(如"hello")调用了free() - 确认没有把指针算术结果(如
p + 1)传给free()—— 必须是原始分配返回值
示例错误:
int* p = new int[5]; free(p); // ❌ 混用 new 和 free,UB,后续可能触发 invalid pointer
用 AddressSanitizer 快速定位越界和释放后使用
不用手动加日志或反复注释,直接启用编译器内置工具:
- Clang/GCC 下加编译选项:
-fsanitize=address -g - 运行时报错会精准指出:哪一行越界读写、哪一行释放后使用、哪一行向
free()传了非法地址 - 注意:ASan 会替换
malloc/free实现,因此能捕获多数堆错误,但无法检测栈溢出(需-fsanitize=undefined辅助) - 避免在 ASan 开启时链接某些旧版第三方库(可能有符号冲突)
典型 ASan 输出:
ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000014 at pc 0x00010a... bp 0x7ffee... sp 0x7ffee...
READ of size 4 at 0x602000000014 thread T0
#0 0x10a... in main example.cpp:12
0x602000000014 is located 4 bytes inside of 20-byte region [0x602000000010,0x602000000024)
freed by thread T0 here:
#0 0x10b... in operator delete[](void*) asan_new_delete.cc:177
#1 0x10a... in main example.cpp:10
警惕隐式指针偏移和容器封装陷阱
有些看似安全的操作,实际悄悄修改了指针值:
-
std::vector::data()返回的指针,在push_back()或resize()后失效;若缓存了该指针并后续free(),就是非法地址 - C 风格封装中,常见「在分配内存前额外申请几个字节存长度」,然后返回
p + sizeof(size_t);这时free()必须传原始p,而非偏移后的指针 - 使用
std::unique_ptr或std::vector替代裸指针,可从根本上规避这类错误 —— 但前提是不通过.get()拿指针去free() - 检查是否用
realloc()后没更新所有持有该指针的变量(realloc()可能移动内存,返回新地址)
容易忽略的一点:C++ 标准库容器(如 std::string)内部缓冲区不可直接 free(),哪怕你用 .c_str() 拿到指针也不行。
排查时优先看报错前最近一次 free() 或 delete 调用,再逆向追踪该指针的来源——它大概率不是“看起来那个”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











