c 用引數返回堆上的空間

2021-06-29 03:20:40 字數 1811 閱讀 8386

《高質量c++和c程式設計》7.4 指標引數是如何傳遞記憶體的一節中寫道:

void getmemory(char *p, int num) 

void test(void)

無法返回記憶體,可以用如下方式

void getmemory2(char **p, int num) 

void test2(void)

個人的理解就是,實際上指標傳遞仍然是一種值傳遞,只不過在引數是指標的時候,傳遞的是指標的副本,這樣你在位址上的操作實際就反映到了記憶體中,舉個例子來說,假設有乙個函式

void fun(int  *p)

當用呼叫時fun(q),會產生實參的乙個副本設為_p,函式體為副本_p分配了記憶體,實際上並未改變實參p,這就是getmemory沒有成功的原因。相反,如果我們有如下函式

void fun(int

*p)

在這個函式中,當發生實參呼叫的時候,仍然會產生實參的副本,但是注意這裡不是改變副本,而是改變副本指向的記憶體中的內容,這裡p是乙個整形指標,在記憶體中佔四個位元組,副本和實參指向同一片記憶體,所以當你

在以副本為位址的記憶體內賦值3,實際也就是改變了實參指向的記憶體中的內容。

總結一下就是:指標傳遞仍然是值傳遞,所以我們在函式體內只有操作*p才會達到我們的指標傳遞要求,而不是操作p,這樣操作只在副本上,實際並不反映到實參指向的記憶體。

書中另一種方法是:

char *getmemory3(int num) 

void test3(void)

實際是將堆的特性和return相結合,堆上分配的內存在函式不會釋放,而return實際返回的p的乙個副本,但是這裡的副本是乙個指標,簡單的說是乙個記憶體位址,而這個位址在函式結束後並沒有釋放,所以,我們可以繼續使用。如果是普通的區域性變數,return返回它的乙個副本,隨後區域性變數隨著函式的結束而被釋放,這在某些時候會引起麻煩,比如

char *getstring(void) 

void test4(void)

至於return似乎還有東西說,一時想不起。。。

事情總有例外,今天小妞找我除錯程式,發現了一件很奇特的事情,看**

void getarray(char **s, int n)

int i = 0;

while(i < n)

in.close();

}int main()

return

0;}

這個程式可以正確編譯執行。而下面**:

void getarray1(char **s, int n)

int i = 0;

while(i < n)

in.close();

}int main()

return

0;}

這個**確實在執行時出錯

分析了一下,個人認為雖然兩個函式的引數都是char **s,但是乙個在main()中先分配,乙個直接在getarray中分配,原因就在於此,getarray函式在main函式中先分配了記憶體,然後傳遞給它,雖然仍然是值傳遞,但是s的元素是指標,getarray函式中在main函式分配的記憶體上完成了操作,所以當函式結束時,所有操作仍然保留下來。getarray1函式不同,它是在函式體內完整分配記憶體,然後施加操作的,相當於都在副本上,所有操作都不會在函式結束後保留下來。

這是個人的一點理解,如有不對的地方還請指教。

C 用引數返回結果與用返回值返回結果的思考

xvkbuffer作為引數比寫為返回值的好處是 1,xvkbuffer可以是堆變數或棧變數,若寫為返回值則只能是堆上申請,因為必須保證它的永久性 2,xvkbuffer或作為棧變數返回顯然是不行的,因為它不持久 void xvulkan createbuffer vkbufferusageflagb...

C 的命名空間 預設引數

命名空間 1 使用目的 對識別符號的名稱進行本地化,以避免命名衝突或名字汙染。命名空間的定義 includeusing namespace std namespace n1 n1為命名空間的名稱 命名空間可以巢狀 同乙個工程中允許存在多個相同名稱的命名空間,編譯器最後會合成同乙個命名空間。注 乙個命...

MyBatis的返回引數

mybatis的返回引數型別兩種 1.對應的分類為 resultmap resulttype 2 對應返回值型別 resultmap 結果集 resulttype int,string long class 3.注意點 在mybatis進行查詢對映時,其實查詢出來的每乙個屬性都是放在乙個對應的map...