關於指作為針形參與返回值的常見問題
1、返回棧中局部變量的地址
#include <stdio.h> int *fun(){ int a = 10; // a為當前方法棧中的局部變量,結束即釋放 return &a; // 所以傳遞出去的會是一個無效(非法)地址 } int main(int argc, char const *argv[]) { int *a = NULL; a = fun(); *a = 100; // error,操作非法內存 printf("a = %d\n", *a); return 0; }
2、返回data區的地址
代碼同上,不同之處在於a加個static,變為靜態局部變量,等同於全局變量
#include <stdio.h> int *fun(){ static int a = 10; // 靜態局部變量,不會隨着方法棧自動釋放 return &a; // 返回的是有效地址 } int main(int argc, char const *argv[]) { int *a = NULL; a = fun(); *a = 100; // ok printf("a = %d\n", *a); return 0; }
3、指針作為形參傳遞(一)
#include <stdio.h> #include <stdlib.h> void fun(int *tmp){ tmp = (int *)malloc(sizeof(int)); // 形參局部指針變量只在當前方法棧中有效 *tmp = 100; // 當前棧中tmp動態分配的內存未釋放,造成內存泄漏 } int main(int argc, char const *argv[]) { int *p = NULL; fun(p); // p是空指針,沒有指向,把p的值傳給tmp printf("*p = %d\n", *p); // error 操作空指針所指向的內存 return 0; }
此時fun()函數和main()函數同級,tmp作為fun中的形參局部變量,對其操作不會影響main中的實參p;
並且給tmp在堆中動態分配內存,但是tmp隨着fun方法棧的釋放而消失,堆中的內存沒有釋放,造成內存泄漏。
4、指針作為形參傳遞(二)
#include <stdio.h> #include <stdlib.h> void fun(int *tmp){ *tmp = 100; } int main(int argc, char const *argv[]) { int *p = NULL; p = (int *)malloc(sizeof(int)); fun(p); // 值傳遞 printf("*p = %d\n", *p); // 100 return 0; }
此時在fun()函數中操作的不是指針變量tmp,而是tmp所指向的堆內存(沒有改形參本身),也就是fun()方法棧中和main()方法棧中的兩個變量tmp和p指向了同一塊堆內存,fun()方法棧的釋放並不會影響操作結果
5、指針作為返回值
#include <stdio.h> #include <stdlib.h> int * fun(){ int *tmp = NULL; tmp = (int *)malloc(sizeof(int)); // 在堆中分配內存 *tmp = 100; // 堆內存賦值 return tmp; // 返回堆區地址,函數調用完畢不釋放 } int main(int argc, char const *argv[]) { int *p = NULL; p = fun(p); printf("*p = %d\n", *p); // 100 // free :堆區空間需要手動釋放 if (p != NULL) { free(p); p = NULL; } return 0; }
和第3的區別在於不是通過形參給變量賦值,而是直接返回了指針變量,注意:這里返回的不是棧區的局部變量地址(第1),而是堆區的地址,堆區變量是不會自動釋放的,所以返回是合法的。
指針指向同圖4