怎樣通俗地解釋「堆棧溢出」是什麼?


簡單點兒說,就是堆棧 溢出了唄。

溢出 就是堆棧滿了,還往裡面塞東西。

老實說上面所謂通俗的解釋,在我看來沒有一個靠譜的,除了抖機靈和吐名詞,根本沒有解釋問題么。

剛剛已經說了,堆棧溢出就是堆棧滿了,還往裡面塞東西,然後就掛了。

那麼堆棧是什麼?如果計算機是一個白領的話,那麼堆棧就是他的辦公桌。為了完成老闆(程序)交代的工作,這個白領需要從書架或者柜子里拿出資料出來核對處理。所謂的堆棧溢出就是為了解決一個任務,所需要的資料或者所處理的臨時數據太多了把桌子堆滿了,然後這個白領就罷工了。。。。

但一般情況下,這個辦公桌是足夠大的,所以堆棧溢出一般都是老闆(程序)交代的工作出現了問題。最常見的就是無限遞歸,例如為了解決問題A,必先解決問題B,要解決問題B,必須解決問題A,這時候這個這個白領不斷的寫筆記解決問題A,解決到一半又要寫筆記解決問題B,還沒弄完又要寫筆記解決問題A,如此反覆,很快桌子就被筆記堆滿了(溢出了)。


老公洗一堆盤子,洗完一個就疊在旁邊。

桌面比較小,只能一個個疊在一起。

然後老婆會幫忙把盤子一個個從上到下取出,安放在廚櫃裡。

如果老婆手腳太慢,那麼可能疊得太高,老公沒空間放盤子了,那麼就得停下來沒法洗了。

盤子 = 數據

疊起來的空間 = 堆棧

盤子沒位置放 = 堆棧溢出

==============================

2014/8/2 更新一下概念問題。

通常「堆棧溢出」是指「調用堆棧(call stack)的溢出」。要通俗地解釋調用堆棧可能比較困難,因為它涉及許多其他計算機架構的知識。而這個答案只是簡單地解釋堆棧這種數據結構的特點──先進後出/後進先出。溢出是指這個數據結構滿溢,不能存放更多數據。其他的數據結構也會遇到這個情況。即使數據結構並非固定容量,而是可擴展的,在有限的內存空間下仍是有滿溢的機會。

另外,很多時候,「調用堆棧溢出」的出現是與遞歸(recursion)相關的。我們可以把一些遞歸的實現改為迭代(iteration),但有時還是必須有一個自定義的堆棧數據結構,例如對樹的深度優先搜索(Depth-First Search, DFS)。自定義的堆棧也是有溢出的可能。

所以,雖然堆棧溢出常指調用堆棧溢出,但我認為本質上也只是一種數據結構的滿溢情況。對於缺乏計算機知識的對象,可能可以先解釋堆棧這種數據結構,有機會才更深入解釋如何用這種數據結構實現函數調用及函數內的局部存儲。


2.stack overflow --- please keep in mind that the default stack size is 8192K.

以下是演示,需要debug版本。(release版本會有比較大幅度優化,看不到結果的)。

int f(int x)

{

return f(x+1);

}

int main()

{

int y = f(1);

return 0;

}

---------------------------------

看了上面很多比喻也好,基本在解釋什麼是stack,不僅讓人哭笑不得。。。。。。。。

難道連「什麼是棧」和「什麼是棧overflow」兩個問題都區分不清嗎,人家並沒有讓你解釋什麼是LIFO啊,所以你說棧的pop操作簡直就是驢唇不對馬嘴,似是而非,根本沒看清楚問題是什麼。。。

很可能這個問問題的人只是聽說過 stack overflow, buffer overflow 這樣的術語,就來問了。

答案當然也顯而易見了,幾個字就可以回答的事情為什麼還要扯那麼遠呢,stack 是有向低地址增長的說法,但是堆沒有增長方向一說,所以畫那個方向的箭頭幹什麼呢?豈不是讓人誤以為堆也是和stack類似的內存管理方法?


保健寺的花和尚王富貴找到了一個有很多姿勢的網站,但他沒有紙,只好把網站的URL抄在手串的念珠上,但珠子太小,每個珠子只能抄一個字母。然後他發現把珠子挨著寫了一遍,還沒抄完。再寫就把前面的字覆蓋了。富貴眼前一藍,昏倒了。

5分鐘後,王富貴恢復了知覺,心中暗罵。。。老子要是有方丈脖子上的大串念珠就好了。。。看來是該花錢升級下硬體了。


吃多了吐


感謝邀請,棧是一種後進先出的數據結構,堆棧也是採用這種結構管理內存,調用過程中當最初的結果依賴於後面的計算處理,那麼後面的部分雖然後開始處理,卻先結束。當後續處理太多並且又依賴更後面的處理......(比如遞歸),便會一直壓棧,當空間全部用完,就會造成「堆棧溢出」。還有一種經常同棧配合使用的數據結構,叫做隊列,隊列是先進先出,比如排隊買票。

————————————通俗分割線——————————

X去吃金錢豹,錢交了,一種「回本」的念頭油然而生,於是......(省去幾千字),1小時後,X感覺吃得好撐,需要上廁所,恭喜他,這屬於隊列溢出,10分鐘後禮畢,繼續吃。另一種情況是這樣:1小時候,X感覺吃得好撐,卻又不想上廁所,只是看著眼前的奶油酥皮湯一陣陣噁心,想吐,1分鐘後果然技驚四座,這就是棧溢出。一般來講棧溢出都比較可怕。


收到一個邀請回答這個問題,雖然很老的問題了,大家也都說得很清楚了,但我還是試著寫兩句。其實堆棧溢出從原理上來講是十分容易理解的,前面各位大神也都寫得很清楚了。我想也許提問者更多想知道的是它的應用,因為日常提到堆棧溢出的時候95%是因為這個名詞導致了什麼什麼的發生。堆棧溢出有什麼應用呢?這玩意本身是程序中的一個漏洞,是程序員的疏忽導致的。從廣義上來講,更大意義上我們是在「溢出」上做文章,這多是由於程序員沒有做大小檢查、邊界檢查……等等各種檢查,而將超出大小的內容放到一定的空間里導致的。溢出之後的代碼執行具有很大的不確定性,至少它不會按照程序員本來的意思再執行下去,因此通常被作為可攻擊的漏洞,往往被攻擊者所利用。例如,它可以讓攻擊者轉而執行它自己的代碼,讓程序做意想不到的事情(例如前面有人說「可能是上傳你的A片種子?也可能是啟動一個木馬控制你的攝像頭打造你自己的XX門」,這都是有可能的),或者是提升自己的許可權,獲得更高級別的系統許可權從而為後面的行為做準備,等等。今年讓業界大為震動的SSL Heartbleed本質上就是一個溢出漏洞(雖然不是簡單的堆棧溢出),可見這玩意的影響有多麼大,發生起來是多麼普遍(或者說容易發生、容易被利用);這也是段子手們拿溢出這玩意說事從而YY出掃地僧系列段子的原因之一。


【溢出】從字面意思理解就可以,就是超出了限定範圍。

【堆棧】在計算機不同的場景會被理解成不同的意思:

1. 在數據結構理論方面,堆棧是指一種數據結構,堆結構,棧結構,抽象的概念,《演算法導論》或者《數據結構預演算法分析》里寫的很清楚;

2. 在計算機內存應用場景中,在不同的計算機體系結構下,程序使用內存的方式存在幾種區別,其中就有「堆」段和「棧」段,其他還有比如代碼段,數據段,BSS段,等

而這裡說的【堆棧溢出】,就是指第2種意思,一句話概括就是【合法內存使用範圍之外的非法越界】,而這種越界一般通常出現在堆段和棧段這兩個區域,所以被叫做【堆棧溢出】,形象點理解可以看 @Milo Yip大神的解釋。

堆段和棧段以及其他段都是每個程序一啟動就需要分配好的區域,區域之間由虛擬地址隔離,由編譯器和操作系統保障互相不會交叉。

堆段的溢出形式比較常見,最簡單的就是C語言中動態malloc了固定大小的地址空間,然後memcpy時超出了這個固定空間的範圍,錯寫了合法空間範圍之外的區域,很可能因此損壞了其他變數的值

棧段也同理,比如一個char tmp[16]的數組,你在strcpy的時候寫入了16位元組以上的字元,這樣就錯寫了tmp地址範圍外的區域,棧的溢出傷害就大了,很容易寫壞函數調用的保護現場數據,導致segmentation fault後core dump的back trace都是亂的,debug都很困難了。

另外使用遞歸方式寫的函數,在使用中遞歸層級過多耗光了程序的棧空間,也是棧溢出。

堆棧溢出算是寫C代碼時犯的比較低級的錯誤了,一定要養成規範編碼的好習慣,每次變數賦值的時候都注意一下,最好不用memcpy或者strcpy,改用memncpy或者strncpy。

水平有限,就解釋這麼多,如有錯誤還望大家指正。


如果「溢出」這個詞還不能讓他理解這個詞的描述的現象的話,那估計要很久他才能理解了


謝邀。

認真的人一定會指出,堆是堆棧是棧。

不過題主要的是通俗解釋,那就抖個機靈吧:

堆棧溢出就是你再給電腦講那個從前有座山的故事,然後電腦聽煩了,告訴你他已經忘記這個是故事中的第幾層故事,然後她就拒絕再聽下去了。

原因就是電腦她是處女座,把每一層故事裡的廟啊,老和尚啊,小和尚啊都給記下來了,以備你後面提到他們。可是她記名字那張紙很小,寫不下那麼多人。


有一個水桶,倒水可以慢慢往裡面倒,舀水只能從上面開始舀。

但桶是有容量的,有一天,你倒水倒滿了,漫出來了,於是就「堆棧溢出」了。就這樣。


你買了個1L的水桶,然後每次裝的時候裝一杯,用的時候倒出一杯。如果已經裝滿了1L,想再倒進一杯?得,溢出了吧。如果水桶已經空了,你拿個杯子想再倒出一杯?得,出來的是空氣,這個也叫溢出。(怎麼會有人邀請我…)


其實我很疑惑為什麼需要『通俗』地來解釋這個術語,不搞這個的話也沒必要懂這個,不過我恰好想到一個非常合適的比喻:

初中高中正規點的考試都會給你張答題紙答題,答題紙上每道題都是有固定大小的,會用專門的掃描儀把每道題掃出來分發給負責各個部分的老師去批改。你把答案寫出了這個範圍,那就『溢出了』。溢出是很嚴重的,出現在程序里,你的程序經常會掛掉,出現在考試里,你的考試也很可能掛掉。

這個比喻真的非常恰當,甚至它導致你掛掉的原因都可以類比。對於棧,溢出通常會導致無意修改了別的臨時變數的值甚至是調用信息;對於堆,溢出可能會破壞分配器維護的鏈式結構;對於考試,溢出一方面讓看原來那道題的老師找不到你的答案,一方面讓看你溢出到的那道題的老師被一堆不明所以的式子亮瞎狗眼,然後你兩道題就都撲街了。

所以想想還是考試溢出比較可怕。


長度不可變的棧都存在溢出的可能,這個取決於棧的實現。

象操作系統的 C 函數調用棧 就是固定長度,當你在一個函數內分配了一個棧上對象時就有可能溢出。某些嵌入式系統,函數調用棧可能只有幾 K ,PC 上的線程一般也就幾 M 的棧空間。在這些系統上,體驗棧溢出只需在某個調用函數內定義個大數組即可。

如果你在 C 裡面自己實現一個棧,除非你設定了棧空間的最大值,否則沒有棧溢出,只有內存分配失敗。


」媽的,這破公交車,根本擠不進去了,怎麼還有人擠啊,快把老子擠下車了。」


有個身高180,體重250的朋友叫小B,

有一次我、小B、小C、小D、小E 出去喝酒,

因為小子們想試探一下小B到底酒量有多深,

就輪番轟炸灌啤酒,

過了很久..................

小B在去了很多次WC後,

終於堅持不住了,

最後一杯下肚,

毫無徵兆的噴涌而出,

小子們樂道:「卧槽,溢出了!」


反對 @Milo Yip的答案,概念理解有誤。

不是處理速率跟不上,而是空間不足。如果同樣用盤子的例子來解釋應該是這樣的:

老公自己做了一個能放X個盤子的櫥櫃,結果老婆買了Y個盤子(X&>Y),然後讓老公把這Y個盤子放進櫥櫃裡面。

接下來的操作就是,老公為了把這Y個盤子放進去,做了一件事情,抽出Z個盤子扔老婆臉上:叫你手賤

當然,老婆可以控制Y的數量,然後去分析扔出來的Z是多少,然後進行攻擊。


為啥我會被邀請來回答問題??好神奇。。第一次發生。。。

==========================================================

學者去向禪師請教,坐,禪師往學者杯中倒茶,杯滿仍到,溢出還倒,學者不解,問,茶已溢出為什麼大師還往裡面倒?禪師:你來向我請教,如果不把你心中已有的東西都倒出來,就象這杯中水一樣,我怎麼能再倒倒進去水呢?

==========================================================

這篇小故事其實蘊含禪機,講了入棧、溢出、出棧,是不是很神奇咧~~

為了切題,我只說一句:茶溢出了,就是「堆棧溢出」。


我理解的堆棧溢出 就是棧這個容器已經放滿了 再往裡放東東 東東就往外冒了。


辦事大廳滿了,就是這麼個意思。


推薦閱讀:

在人類史上,有哪些創新是由於未能成功商業化,而被我們錯過的?錯過的原因是什麼?
學什麼技術好 不枯燥 穩定?
我現在是上班狀態但是自己現在什麼技術,甚至不知道自己應該幹什麼工作,怎麼辦?

TAG:互聯網 | 技術 | C編程語言 |