程序例子如下:

  1 #include <stdio.h>

  2 #include <stdlib.h>

  3 

  4 void func(int *p , int n)

  5 {

  6     printf("line 6 %p\n",p);

  7     p = malloc(n);

  8     printf("line 8 %p\n",p);

  9     if (p == NULL)

 10         exit(1);

 11     return ;

 12 }

 13 

 14 int main ()

 15 {

 16     int size = 100;

 17     int *p=NULL;

 18     printf("lin 18 %p\n",p);

 19     func(p,size);

 20     printf("line 20  %p\n",p);

 21 

 22     free(p);

 23 

 24     exit(0);

 25 }

  程序的执行过程中,不会报任何错误,就是动态申请空间和释放空间的过程。15行定义了一个指针类型的变量。16,调用了自定义的func函数,并且传递参数p和size。问题就是出在参数传递上。

   wKiom1aniTzBIMqhAACFbZSO-EQ963.png

   p是一个地址,但是main 函数调用func(p,size)的时候实际进行的传值调用。所以,在main中释放p会导致在func子函数中申请的空间无人释放的问题。

  解决办法:

  一、采用二级指针的方式。使得main中的p 和 func子函数的中的是同一个地址。

  代码如下:

  1 #include <stdio.h>

  2 #include <stdlib.h>

  3 

  4 void func(int **p , int n)

  5 {

  6     printf("line 6 %p\n",p);

  7     *p = malloc(n);

  8     printf("line 8 %p\n",p);

  9     if (p == NULL)

 10         exit(1);

 11     return ;

 12 }

 13 

 14 int main ()

 15 {

 16     int size = 100;

 17     int *p=NULL;

 18     printf("lin 18 %p\n",p);

 19     func(&p,size);

 20     printf("line 20  %p\n",p);

 21 

 22     free(p);

 23 

 24     exit(0);

 25 }


  wKioL1ani7TQaXd4AABOr4B9mIw737.png 

   需要深入理解,到底什么时候二级指针,在本例子中,二级指针可以实现传递的p本身而不是副本到func函数中。func函数申请到的100字节的动态内存空间的起始地址就是保存在func和main中的p这个指针变量中。此时在main中free不会导致内存泄露。

  方法二:返回指针的方式:

   

  1 #include <stdio.h>

  2 #include <stdlib.h>

  3 

  4 void * func(int *p , int n)

  5 {

  6     printf("line 6 %p\n",p);

  7     p = malloc(n);

  8     printf("line 8 %p\n",p);

  9     if (p == NULL)

 10         exit(1);

 11     return p ;

 12 }

 13 

 14 int main ()

 15 {

 16     int size = 100;

 17     int *p=NULL;

 18     printf("lin 18 %p\n",p);

 19     p = func(p,size);

 20     printf("line 20  %p\n",p);

 21 

 22     free(p);

 23 

 24     exit(0);

 25 }

  通过返回地址得方式,让main中p指向100字节的动态内存空间,在main结束的时候,free这100个字节的内存空间,显然不会导致内存泄露。

  总结:本例子,想从参数传递的角度,探讨传值和传址的不同。对普通变量而言,传址就是传递变量的地址。但是对指针变量要想传递地址,就需要使用二级指针。指针是地址不错,但是存放指针的内存单元也需要有地址。就是传递存储该内存单元地址【也就是二级指针】,就可以实现在主调和被调函数之间使用同一指针操作。