我有一个非常大的代码,包含malloc,free,循环等。有时,由于我在程序的一个部分收到错误,我需要很长时间才能找出问题所在,但是真正导致问题的是什么在代码中是遥远的东西。大多数问题都是由于我没有注意到的双重免费造成的。但是其中一些在一段时间内工作正常然后崩溃了。
所以,考虑一个大多数时间都有效的例子:
int main() {
char *x = (char*) malloc(10);
char *y = (char*) malloc(10);
free(x);
free(y);
x = (char*) malloc(10);
free(y); // Am I lucky?
return 0;
}
为什么在运行第二个free(y)
时没有收到错误?我检查了第二个x
之后malloc
的指针是否等于先前分配的地址y
。它并不总是有效。有时会崩溃。
所以,我的问题是:在尝试双重免费时有没有办法强迫错误?
谢谢!
答案 0 :(得分:3)
在free()之后,将指针设置为null
以避免"释放"相同的地址。
Free()不会更改指针的值,因此程序可以重用该地址来分配新块。
Free(null)不执行任何操作,也不会破坏您的代码。
答案 1 :(得分:2)
如您所述,如果它没有崩溃,x
和y
指向同一个区块。这是因为malloc
正在为您提供刚刚释放的块。 free
不知道您使用的是什么指针。所有它关心的是它所指向的。
我的建议是,在释放指针指向的内存后,将其清除(将其设置为NULL)。这样,您就不再有悬空指针了。换句话说,改变
free(x);
到
free(x);
x = NULL;
答案 2 :(得分:1)
调试堆可能会立即捕获大多数双重自由问题。
使用Microsoft的编译器,默认情况下会使用使用调试运行时的构建获得调试堆。
正如Basile Starynkevitch在评论中提到的那样,您可以在Linux上使用像valgrind这样的工具来检测这些问题,但是如果您想要更简单的开始,可以使用MALLOC_CHECK_
环境启用调试堆变量。类似的东西:
MALLOC_CHECK_=1 ./myprog
或在gdb调试器下运行程序,默认情况下将启用堆检查。
请注意,malloc()
设置无法检测到程序中的特定错误(假设第三次调用MALLOC_CHECK_
返回刚刚释放的指针)。为了解决这样的问题,我建议不要将释放的指针设置为0(或NULL
),而是将它们设置为已知的坏标记值:
#define INVALID_PTR ((void*) -1)
// ...
free(y);
y = INVALID_PTR;
这样就可以实现这一目标,而不是隐藏你双重释放y
的事实,你的程序会快速失败"关于那个bug。
答案 3 :(得分:1)
总是习惯于像这样声明指针变量:
int* foo = NULL;
然后你可以分配指针并做任何你想做的事情,然后解决这个问题:
if (foo != NULL) free(foo);
foo = NULL;
这样你以后就可以避免很多麻烦。