棧記憶體指標的問題

2021-09-30 06:03:15 字數 2153 閱讀 9689

這幾天在學習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語言上,使用malloc等記憶體分配函式獲取記憶體既是從堆中分配記憶體,而在乙個函式體中例如定義乙個陣列之類的操作是從棧中分配記憶體。

char * p這個p指標是儲存在棧中的,但它的內容是你malloc的堆記憶體的位址,return

p時,不是返回p的位址,而是p指向的位址內容.這個時候,由於p指向的位址內容是用malloc在堆上分配的,所以是有效的.

動態記憶體堆,c++中由new和delete來分配和釋放,c中由malloc和free來分配和釋放,它的生命週期是動態的,可以由程式設計師來建立和銷毀。當然程式結束自動釋放。

return p;的時候會在記憶體中產生乙個匿名的指標,子函式執行結束p變數消亡,執行語句str = getmemory(100);

此時匿名指標變數賦值給str指標。

至於記憶體空間,由於是在堆中申請所以沒有顯示的釋放,則會在程式結束才被釋放,也就是在free之前,該空間一直存在。

棧記憶體問題

棧記憶體問題排查 編譯時增加 g 和安全編譯選項 fstack protector g 生成除錯資訊,用於後續gdb除錯 fstack protector 在編譯時會在函式棧框中插入乙個canary,並實現了通過這個canary來檢測函式棧是否被破壞 如果程式執行過程 現越界執行到canary隨機數...

棧 進棧,出棧指標修改的順序問題

策略 設計乙個順序棧,附設的top指標有兩種策略 借助一篇文章深入分析二者的異同。top指向棧頂 首先令top指向當前棧頂元素,這樣進來乙個新的元素時,新元素不能佔據當前top指向的位置,需要把top指標挪一挪,一般是top 但不排除題目中設計的是top 不管怎樣,都是把top指標往棧外拓展乙個空位...

return不能返回指向棧記憶體的指標

棧是臨時的 當跳出棧時,其指標對應的值被下次壓棧替換掉 可能每次出棧時,系統可能會對剛才壓棧的記憶體初始化 include uisng namespace std char getstring int main 此程式中,return返回的是指向棧記憶體的位址,程式編譯警告,因為給該內存在函式結束時...