值傳遞, 指標傳遞?
這幾天在學習c過程中,在使用指標作為函式引數傳遞的時候出現了問題,根本不知道從何得解:源**如下:
createnode(binnode *tree,char *p)
該**段的意圖是通過乙個函式建立乙個二叉樹的節點,然而在,呼叫該函式後,試圖訪問該節點結構體的成員時候,卻發生了記憶體訪問錯誤,到底問題出在哪兒呢?
一直不明白指標作為函式引數傳值的機制,翻開林銳的《高質量c/c++程式設計指南》,找到了答案。
[如果函式的引數是乙個指標,不要指望用該指標去申請動態記憶體]
原來問題出在c編譯器原理上:編譯器總是要為函式的每個引數製作臨時副本,指標引數tree的副本是 _tree,編譯器使 _tree = tree。如果函式體內的程式修改了_tree的內容,就導致引數tree的內容作相應的修改。這就是指標可以用作輸出引數的原因。
即上面的函式**經過編譯後成為:
createnode(binnode *tree,char *p)
如果沒有
_tree = (binnode *) malloc(sizeof(binnode));
這個語句,在函式體內修改了_tree的內容,將會導致引數tree的內容作相應的修改,因為它們指向相同的記憶體位址。而
_tree = (binnode *) malloc(sizeof(binnode));
這個句,系統重新分配記憶體給_tree指標,_tree指標指向了系統分配的新位址,函式體內修改的只是_tree的內容,對原tree所指的位址的內容沒有任何影響。因此,函式的引數是乙個指標時,不要在函式體內部改變指標所指的位址,那樣毫無作用,需要修改的只能是指標所指向的內容。即應當把指標當作常量。
如果非要使用函式指標來申請記憶體空間,那麼需要使用指向指標的指標
createnode(binnode **tree,char *p)
上面的是林銳的說法,目前來說不知道怎麼去理解,不過可以有另外的方案,通過函式返回值傳遞動態記憶體:
binnode *createnode()
這個倒還說得過去,因為函式返回的是乙個位址的值,該位址就是申請的記憶體塊首位址。但是,這個容易和另外的乙個忠告相混繞
[不要用return語句返回指向「棧記憶體」的指標,因為該內存在函式結束時自動消亡]
這裡區分一下靜態記憶體,棧記憶體和動態分配的記憶體(堆記憶體)的區別:
(1) 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在。例如全域性變數,static變數。
(2) 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
(3) 從堆上分配,亦稱動態記憶體分配。程式在執行的時候用malloc或new申請任意多少的記憶體,程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多。
因此,試圖返回乙個棧上分配的記憶體將會引發未知錯誤
char *getstring(void)
p是在棧上分配的記憶體,函式結束後將會自動釋放,p指向的記憶體區域內容不是"hello world",而是未知的內容。
如果是返回靜態儲存的記憶體呢:
char *getstring(void)
這裡「hello world」是常量字串,位於靜態儲存區,它在程式生命期內恆定不變。無論什麼時候呼叫getstring,它返回的始終是同乙個「唯讀」的記憶體塊。
[參考:林銳《高質量c/c++程式設計指南》]
指標作為函式引數傳遞
任何程式語言的引數傳遞實際上都是在做傳值呼叫.所謂的傳指標,就是把指標指向者的位址 乙個值 傳進函式.也就是那個位址被壓棧.然後我們再通過這個位址進行操作,因為實參和形參同樣都是乙個位址的值.所以改變形參指向者的狀態時,實參指標也能看到這種變化.這裡區分一下靜態記憶體,棧記憶體和動態分配的記憶體 堆...
函式指標作為引數傳遞給函式
函式指標同樣是可以作為引數傳遞給函式的,include include using namespace std int test int int test2 int ra int int void main int argc,char argv coutfp fpi fpi test fpi賦予te...
指標作為引數傳遞
如果想通過函式呼叫得到n個要改變的值,可以採取下面的步驟 在主調函式中設n個變數,用n個指標變數指向它們 編寫被呼叫函式,其形參為n個指標變數,這些形參指標變數應當與主調函式中的n個指標變數具有相同的基型別 在主調函式中將n個指標變數作實參,將它們的值 是位址值 傳給所呼叫函式的n個形參指標變數,這...