程序例子如下:
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。問題就是出在參數傳遞上。
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 }
需要深入理解,到底什麼時候二級指針,在本例子中,二級指針可以實現傳遞的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個字節的內存空間,顯然不會導致內存泄露。
總結:本例子,想從參數傳遞的角度,探討傳值和傳址的不同。對普通變量而言,傳址就是傳遞變量的地址。但是對指針變量要想傳遞地址,就需要使用二級指針。指針是地址不錯,但是存放指針的內存單元也需要有地址。就是傳遞存儲該內存單元地址【也就是二級指針】,就可以實現在主調和被調函數之間使用同一指針操作。