1. 程式人生 > >面試題之程式語言

面試題之程式語言

堆記憶體和棧記憶體:

一個由C/C++編譯的程式佔用的記憶體分為以下幾個部分 :
1、棧區(stack)—由編譯器自動分配釋放 ,存放函式的引數值區域性變數的值等。其操作方式類似於資料結構中的棧
2、堆區(heap)— 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由OS回收(為什麼是可能呢?如果是C,就不會回收,如果是帶有垃圾回收機制的語言,比如python和java 就會回收)。注意它與資料結構中的堆是兩回事,分配方式倒是類似於連結串列
3、全域性區(靜態區)(static)—,全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。-程式結束後有系統釋放
4、文字常量區—常量字串就是放在這裡的。 程式結束後由系統釋放
5、程式程式碼區—存放函式體的二進位制程式碼。

棧記憶體和堆記憶體的區別:
第一個區別是記憶體分配,剛剛已經聊過了。
第二個區別是申請後系統的響應:
對於棧:
只要棧的剩餘空間大於所申請的空間,系統將為程式提供記憶體,否則將報異常提示棧溢位。
對於堆:
在記錄空閒記憶體地址的連結串列中尋找一個空間大於所申請空間的堆結點,然後將該結點從空閒結點連結串列中刪除,並將該結點的空間分配給程式。另外,對於大多數系統會在這塊記憶體空間的首地址出記錄本次分配空間的大小,這樣程式碼中的delete 才能正確釋放本記憶體空間。系統會將多餘的那部分重新空閒連結串列中。
第三個區別是申請大小限制:
棧:
在Windows下,棧是向低地址擴充套件的資料結構,是一塊連續的記憶體的區域

。這句話的意思是棧頂的地址棧的最大容量是系統預先規定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小也就是說,棧在哪,棧多大,都是系統定死了的。
堆:
堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。**堆的大小受限於計算機系統中有效的虛擬記憶體。**由此可見,堆獲得的空間比較靈活,也比較大。
第四個區別是分配效率:
棧:
由系統自動分配,速度較快。但程式設計師是無法控制的。
堆:
由new分配的記憶體,一般速度比較慢,而且容易產生記憶體碎片,不過用起來最方便.
第五個區別是儲存內容:
棧:在棧中,第一個進棧的是主函式下一條指令的地址,然後是函式的各個引數,在大多數編譯器中,引數是由右往左入棧,然後是函式中的區域性變數。注意,靜態變數不入棧。出棧則剛好順序相反。
為什麼是這樣呢?
這樣的話,才能讓main知道有啥東西啊。

可程式設計記憶體在基本上分為這樣的幾大部分:靜態儲存區、堆區和棧區。他們的功能不同,對他們使用方式也就不同。
  a)靜態儲存區:記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個執行期間都存在。它主要存放靜態資料、全域性資料和常量。
  b)棧區:在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
  c)堆區:亦稱動態記憶體分配。程式在執行的時候用malloc或new申請任意大小的記憶體,程式設計師自己負責在適當的時候用free或 delete釋放記憶體。動態記憶體的生存期可以由我們決定,如果我們不釋放記憶體,程式將在最後才釋放掉動態記憶體。 但是,良好的程式設計習慣是:如果某動態記憶體不再使用,需要將其釋放掉,否則,我們認為發生了記憶體洩漏現象。

示例程式碼:

int a = 0; 全域性初始化區 
char *p1; 全域性未初始化區 
main() 
{ 
int b; 棧 
char s[] = "abc"; 棧 
char *p2; 棧 
char *p3 = "123456"; 
//123456\0在常量區,p3在棧上。 
static int c =0; //全域性(靜態)初始化區 
p1 = (char *)malloc(10); 
p2 = (char *)malloc(20); 
//分配得來得10和20位元組的區域就在堆區。 
strcpy(p1, "123456"); //123456\0
//放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。 
}