香蕉树上第八根芭蕉——对C指针的认识(一)-内存泄漏和二级指针问题

之前一直对指针问题很多的不解,有了点初步的认识。

提出问题:定义了一个指针参数,然后传递了一个指针变量,为什么改变不了被传递的指针变量,程序如下:

#pragma warning (disable :4996);
#include <iostream>
#include<stdlib.h>
struct mystruct {
	int i;
};
void test1(int *arr, int size)
{
	arr = (int *)malloc(size * sizeof(int));
	std::cout << "test()中新分配地址:" << arr << std::endl;
}
int * test2(int *arr, int size)
{
	arr = (int *)malloc(size * sizeof(int));
	std::cout << "test()中新分配地址:" << arr << std::endl;
	return arr;
}
void test3(int **arr, int size)
{
	*arr = (int *)malloc(size * sizeof(int));
	std::cout << "test()中新分配地址:" << *arr << std::endl;
}
int main()
{
	int *veror = NULL;
	std::cout << "调用test()前veror地址:" << veror << std::endl;
	//test1(veror, 3);
	//veror = test2(veror, 3);
	test3(&veror, 3);
	std::cout << "调用test()后veror地址:" << veror << std::endl;
	system("pause");
	return 0;
}

如果调用test1,结果如下:

如果test2,结果如下:

会发现调用test2是可以完成我们对于改变传入指针值的,但是为什么test1不行呢,原因就是由于函数在传值时会先将veror拷贝一份再传过去,当然就不可以改变原来的值了。那么第三种方法就出来了,那就是指针的指针!

如果调用test3,结果如图:

特别注意的是在调用test3时 一定要取veror的地址,那是为什么呢,为什么这种情况下就可以达到我们所需要的改变了呢,这个就需要一个图来说明,如图

 有了这个图便知,&veror就是将veror地址给了arr这个内存单元里,而且这个内存单元可以指向两级内存,*arr就代表是veror这个内存,而**arr代表veror所指向的内存单元了,这样就可以达到目的了。

之前一直认为说为什么不是将*veror传过去了,原谅我当初有那么傻的想法,以为是指针的指针嘛,就是传下一级别,如果传*veror不就是将最后一级数据内存传过去了嘛,有啥用。所以一定要有个概念就是,函数参数声明的那个只是个声明而已,表示我这个形参是个什么样的人,当你嫁给我了,我就会把你当成我那样的人,哈哈。

但是你有没有想过上面程序最严重问题是什么呢,那就是内存泄漏。什么是内存泄漏呢,就是指说丢失内存,导致堆内存可用减少,通俗的说就是原先用malloc分配了段内存之后,有个指针指向我,不知道哪天,这个指针没了,没了原因可能是局部变量回收了,那这段内存就变成了没人管的孩子。

那么如何去避免内存呢?主要就是在分配之后及时释放回收,有时候又可能会造成二次释放,造成程序异常,可以使用二级指针做一个安全的释放函数。

void safeFree(void **p)
{
	if (*p != NULL && p != NULL)
	{
		free(*p);
		*p = NULL;
	}
}
void test1(int *arr, int size)
{
	int *pp = (int *)malloc(size * sizeof(int));
	std::cout << "test()中新分配地址:" << arr << std::endl;
	safeFree((void**)&pp);
}

这样就可以进行安全释放了!

猜你喜欢

转载自blog.csdn.net/qq_34327821/article/details/81634558