對於C/C++語言程序而言,運行時分配給一個程序的內存通常可以分成四個部分:代碼區、全局/靜態區、棧區、堆區。
代碼區用來存儲需要被執行的指令,例如高級語言編譯彙編生成的二進制文件。
代碼區通常被存放在棧區和堆區的下面來避免棧溢出或堆溢出導致代碼區內容被修改。
全局/靜態區該部分用來存儲靜態或全局變量,它們不是在函數的內部聲明的,並且存在於程序的整個生命週期內。
棧區棧區使用了棧的數據結構(先進後出)
實例運行以下程序內存的分配情況
#includeint total; int square(int x) { return x * x; } int squareOfSum(int x, int y) { int z = square(x + y); return z; } int main() { int a = 4, b = 8; total = squareOfSum(a, b); printf("output = %d", total); }
當程序運行的時候,只有棧頂部的函數在運行,其他部分的函數相當於是被暫停了。當其上方的函數執行完後,它才會繼續運行。
接下來將會運行printf函數
注意:只有需要在多個函數中使用的變量才應當設為全局變量,否則將會造成不必要的內存浪費。
假定分配給程序的棧內存為1MB,但是棧區里的函數佔據的內存大小超過了1MB時就會造成棧溢出,例如寫了一個無限死循環。
堆區和棧區不同的是,堆區的大小不是固定的。程序員可以調整堆區的大小,只要不超過系統的容量,堆區的大小就會一直增長。堆區有時也被稱為自由內存池,堆區具體的實現方式是根據操作系統的架構而定的。但是抽象的來看,堆區就是一個可以靈活存取的內存池。堆區有時候也被稱為動態內存,使用堆區也就指的是動態內存的分配。
注意:堆區的含義並不是數據結構中的堆
由於C語言裡面管理內存的函數能被C++里的new和delete完美實現,這裡只記錄了new和delete的使用方法。
int* p = new int;
使用new以後會在堆區裡面分配一段內存給p,new int會返回一個指針,故應該用int型指針接收。
使用delete會將堆區裡面p的那一段內存清除掉。
例如下面的程序
int main() {
int a;
int* p;
p = new int;
*p = 10;
delete p;
p = new int[20];
delete[] p;
return 0;
}
- 變量a會被存儲在棧中,p使用動態內存在堆區中申請一個大小為4字節的內存空間,將棧區中的變量指向這一位置,並將堆區中的值修改為10
- 使用了delete後,堆區中的記錄將會被清除
- 接下來申請一塊長度為80字節的內存
- 回收這一部分的內存
如果運行下面這段程序就會報錯
#includeusing namespace std; int main() { int* p; *p = 9; cout << "The value at p:" << *p; return 0; }
- 原因分析:
- 這段程序裡面在棧區裡面聲明了一個int型指針變量p,但是卻沒有讓p指向任何內存地址。故直接取p的值會報錯。
- 解決方法:
- 為p在堆區裡面分配一段內存
-
#include
using namespace std; int main() { int* p = new int; *p = 9; cout << "The value at p:" << *p; return 0; } - 將p指向一個棧區內一個變量的地址
-
#include
using namespace std; int main() { int* p; int a; p = &a; *p = 9; cout << "The value at p:" << *p; return 0; }



