通過一個記憶體洩露例子體會引數傳遞
程式例子如下:
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個位元組的記憶體空間,顯然不會導致記憶體洩露。
總結:本例子,想從引數傳遞的角度,探討傳值和傳址的不同。對普通變數而言,傳址就是傳遞變數的地址。但是對指標變數要想傳遞地址,就需要使用二級指標。指標是地址不錯,但是存放指標的記憶體單元也需要有地址。就是傳遞儲存該記憶體單元地址【也就是二級指標】,就可以實現在主調和被調函式之間使用同一指標操作。
轉載於:https://blog.51cto.com/hongyilinux/1738823