连续两次free()同一个指针的报错

程序具有一定规模后,对指针的操作很容易犯错,导致堆破坏。下面主要讲一下用free()释放由malloc()或calloc()申请的空间问题。

先贴一篇论坛比较好的讨论帖:http://bbs.csdn.net/topics/390121909 这篇主要讨论了调用free()主要是释放了什么?

简单的说就是:free()函数释放了指针在堆上指向的空间,这仅是向操作系统表明“这片空间我不要了,你回收吧!”。然而该指针还是指向这片空间,这时若要对这个指针进行读写操作非常危险,容易引发灾难。

好吧,现在进入正题。(以下的分析认为你已经知道上面这些了)

Img是自定义的结构体(不重要),将释放函数写成函数的形式,方便多次调用。

static __inline void free_gaussImg(Img* img)
{	
	if( img )
	{
		if( img->imageData )
		{
			free( img->imageData );
			img->imageData = NULL;
		}
		free( img );
		img = NULL;
	}
}
开始以为这种方式非常好,不仅释放掉空间,还赋上了NULL。自以为可以规避两次连续释放同一个指针所带来的系统的报错,还用了static和inline,然并卵。

free_gaussImg( img1 );
free_gaussImg( img1 );

连写这两条语句后,运行报了堆破坏的错误。要是中断错误指在free_gaussImg内还好说,要是由于这个问题而指向其他地方,就等着哭吧,别问我是怎么知道的,让我哭会。
还是说重点吧!开始以为free_gaussImg()将指针 img1 赋空了,在单步调试的时候发现 img 被赋空了,然而真正的实参 img1 并没有赋空,赋空的只是形参 img。当这时我才意识到这就是指针传值的特点:img1 所指向的空间确实被释放了,而 img1 还是指向该处,再次调用free_gaussImg函数就报错了。正确的做法应该是这样的:

	if( img1 )
	{
		if( img1->imageData )
		{
			free( img1->imageData );
			img1->imageData = NULL;
		}
		free( img1 );
		img1 = NULL;
	}
在要释放img1的地方直接释放赋空,而不能调用函数了。这样不管你释放多少次,都没有问题。

本人知识水平有限,在实践了发现这个问题,并提供了一种解决办法,若您有更好的方法,可以共享一下,大家相互学习。


2017-12-19 更新

如果对于每一种数据类型都写一释放函数,重复的代码自然就增加了,可以用宏解决同一类型的内存释放:

#define void myFree( p )  myFree( (void**)(&(p) )

调用方式为:

void myFree(void **ptr)
{
	if (ptr != NULL  &&  *ptr != NULL){
		free(*ptr);
		*ptr = NULL;
	}
	return;
}
#define myFree(p)  myFree( (void**)(&(p)))

int main(void)
{
	int *nums1 = (int*)malloc(sizeof(int));
	double *nums2 = (double*)malloc(sizeof(double));
	
	printf("before free nums1: %d nums2: %d\n", nums1, nums2);
	myFree(nums1);
	myFree(nums2);
	printf("after free nums1: %d  nums2: %d\n", nums1, nums2);
	myFree(nums1);
	myFree(nums2);
	printf("free again: nums1: %d nums2: %d\n", nums1, nums2);

	return 0;
}

实验结果为:





  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
如果对同一个字符指针进行两次 `malloc`配,会导致内存泄漏和问冲突的问题。 当你对同指针进行多次动态内存分时,只有最后一次分配内存地址会被保存在指针中之前分配的内存地址将丢失。这将导致之前分配的存无法被释放,从而产生内存泄漏。 此外,如果你同一个指针进行动态内存分,并且尝试在每个分的内存块上进行写操作,那么会发生未定义的行为。因为每次分配的内存大小可能不同,访问超出分配的范围可能导致访问非法内存,破坏数据或引发崩溃。 因此,应该免对同一个字符指针进行多次 `malloc` 分配。在重新分配之前,应该先释放先前分配的内存,然后再进行新的内存分配。例如,可以使用 `free` 函数释放先前分配的内存后再进行新的分配。 以下是一个示例,展示了如何正确地释放先前的内存并重新分配新的内存: ```c #include <stdio.h> #include <stdlib.h> int main() { char* ptr = malloc(10); // 第一次分配内存 if (ptr == NULL) { printf("内存分配失败\n"); return 1; } printf("第一次分配的内存地址:%p\n", ptr); free(ptr); // 释放先前分配的内存 ptr = malloc(20); // 第二次分配内存 if (ptr == NULL) { printf("内存分配失败\n"); return 1; } printf("第二次分配的内存地址:%p\n", ptr); free(ptr); // 释放最终分配的内存 return 0; } ``` 在上述示例中,我们先对 `ptr` 进行了一次 `malloc` 分配,然后使用 `free` 函数释放了先前分配的内存。接着,我们再次对 `ptr` 进行了另一次 `malloc` 分配,最后使用 `free` 函数释放了最终分配的内存。 这样,我们避免了内存泄漏,并确保每次重新分配之前都释放了之前的内存。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值