之前一直对指针问题很多的不解,有了点初步的认识。
提出问题:定义了一个指针参数,然后传递了一个指针变量,为什么改变不了被传递的指针变量,程序如下:
#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);
}
这样就可以进行安全释放了!