這個問題是知乎上的乙個問題,看了以後覺得比較有意思。**短到只有十多行,但是這麼短的**卻輸出了很奇怪的結果。很多人回答的時候都是站在理論的角度上說明**的問題,但是實際的問題還是沒有說明其中的問題。
問題是「c 語言區域性變數,堆與棧的問題?」
知乎上的問題
以上就是知乎中的問題,基本上把問題也描述清楚了,對於它的問題看似詭異,其實並不複雜。這個問題涉及幾個知識點,第一是關於記憶體分配的問題,第二是關於函式呼叫時棧幀的開闢與**的問題。當然了,如果是純理論的描述問題,其實只會把問題越搞越糊塗,如果結合偵錯程式問題就不同了。
以下是我在知乎的回答(因為當時回答時隨意了一些,所以這裡再簡單的整理了一下,從分割線開始,就是我整理過的回答了)。
遇到類似的問題,通過在偵錯程式中進行單步除錯,然後再觀察其反彙編**,一般就知道其中的問題所在了。
先來了解幾個簡單的概念性的問題:
首先,區域性變數儲存在棧中;
其次,new 分配的空間在堆中。
棧空間是由 esp 和 ebp 定址(x86架構的平台下),這兩個暫存器是由 cpu 控制維護的。ebp 作為棧幀的基址來說,函式呼叫完後會自動恢復到被呼叫之前,那麼棧中的資料其實還是存在的。esp 作為棧頂指標,在函式返回後,也會被收回。雖然棧幀在函式返回後被**,但是其中的資料並沒有被**,因此之前的資料仍然是存在的。很多書上說,訪問這樣的位址會給出隨機值,其實不是,只是這些值我們不再確定是什麼值而已,但是它不是隨機的。
new 出來的堆空間,如果不 delete 是不會釋放的,也就是說 new 完以後的位址只要不釋放,在其他**中都可以使用。
以上就是 堆 空間和 棧 空間的簡單描述。
上面是理論部分,下面實際觀察一下。
我用的環境是 vs2012,和提問者的環境不同,但是過程是相同的。
看一下 func 函式的反彙編**,這裡我用的 debug 方式編譯的。
在 func 函式的 return 處下斷點,然後執行到此處,觀察其反彙編**,並開啟暫存器視窗、監視視窗和記憶體視窗。
看下面的截圖:
上面的暫存器的值是在 func 函式中的值,看一下 ebp 和 esp 的值。
返回 main 函式,如下圖:
上圖是返回 main 函式後的暫存器的值。
再看 0x0132a670 位址中記憶體的值仍然沒變……
這就是堆的效果,即 new 的情況。
這部分記憶體如果不是人為去寫,一般資料不會被修改或覆蓋。
前面說的是陣列在堆中的情況,如果是在棧中的話,那麼陣列 i 的值都在棧中,即7、9、5 也在棧中。
簡單說一下。
仍然在 func 的 return 處下斷點,執行到這裡,觀察:
此時在 func 函式內,繼續單步返回到 main 函式內:
觀察,現在 esp 和 ebp 已經恢復到 main 函式的棧幀內,而且**也執行到了 main 的 for 內。
但是記憶體的棧中,func 函式內的 i 陣列仍然存在。雖然棧幀被**,但是資料仍在,通常情況是無法訪問它們的,但是現在把 i 的位址返回給 main 函式,因此還是可以訪問到它的。
發現執行到完 call 以後,棧中的資料被破壞了,因為用的是單步步過,其實只要進入 call 以後,原來棧中的資料就被破壞了。
那麼為什麼 7 能被正確的輸出呢?因為在棧還沒破壞之前,7 已經當作 printf 的引數被送入棧中當作引數了。看那句 push edx 即可。
剩下的輸出就不說了,反正棧已經被破壞了。剩下的就理所當然有問題了。
以上就是我給出問題的答覆,其實整個過程還算簡單。記得我在學習的時候,我的老師說過這麼一句話,「學程式設計不看記憶體,相當於游泳不下水」。當然了,也許並不是每門程式語言都有機會去觀察其執行時的記憶體情況,但是,了解如何除錯還是非常有趣的事情,因為很多看似不好解釋的問題,其實在偵錯程式下面都是可以看到問題本質的。
乙個有趣的問題
今早朋友圈某人以100軟妹幣求助這樣乙個問題 概率論是學的一塌糊塗,但是突然想起類似用蒙特卡洛方法可以模擬出來概率。於是向著這100軟妹幣出發了。但是首先遇到了第乙個問題。陣列b的亂序排列感覺有點棘手。首先的第一反應是 迴圈隨機產生1 100的隨機數,判斷陣列中是否已經有該數,若已存在,則重新生成隨...
乙個c語言構造函式呼叫的問題(有趣)
class myclass001 myclass001 int i resolve myclass001 k1 顯示myclass001 k1 1 顯示myclass001 i 其實第二句相當於是在呼叫有int i的那個建構函式,實際上是在給那個建構函式賦值了i。從而呼叫了myclass001 in...
乙個有趣的指標問題
是從網上看到的乙個例子 struct s int i int p void main struct s s int p s.i p 0 4 p 1 3 s.p p s.p 1 1 s.p 0 2 問程式會在哪一行死掉 解答 程式執行到最後一行就會報出異常,死掉.具體解答為 首先需要說明的是結構體s,...