記憶體四區之程式碼區,全域性區,棧區和堆區

ZhiboZhao發表於2021-06-27

C++ 在程式執行時,將記憶體大致分為程式碼區,全域性區,棧區和堆區四個區域。不同的區域儲存不同的資料,賦予不同的生命週期,能夠更靈活地進行程式設計。

  1. 程式碼區:存放函式體的二進位制程式碼,由作業系統管理建立,程式碼區時共享的,對於頻繁被執行的程式,只需要存有一份程式碼即可;
  2. 全域性區:存放全域性變數和靜態變數以及常量,在程式結束後由作業系統釋放;
  3. 棧區:由編譯其自動分配釋放,存放函式的引數值以及區域性變數等;
  4. 堆區:一般由程式設計師通過 new 開闢空間,進行分配和釋放,若程式設計師不釋放,則程式結束時由作業系統回收

下面通過一個例子對全域性區,棧區,堆區的資料宣告週期進行說明:

// 全域性變數屬於全域性區,由作業系統管理釋放
int g_a = 1;
int g_b = 2;
int main(void)
{
	cout << "g_a 的地址為:\t"<< int(&g_a) << endl;
	cout << "g_b 的地址為:\t" << int(&g_b) << endl;
	// 建立普通的區域性變數,屬於棧區
	int a = 10;
	int b = 20;	
	cout << "a 的地址為:\t" << int(&a) << endl;
	cout << "b 的地址為:\t" << int(&b) << endl;
	// 建立靜態變數,屬於全域性區
	static int s_a = 40;
	static int s_b = 50;
	cout << "s_a 的地址為:\t" << int(&s_a) << endl;
	cout << "s_b 的地址為:\t" << int(&s_b) << endl;
	// 程式設計師自己建立變數,屬於堆區
	int* d_a = new int(10);
	int* d_b = new int(20);
	cout << "d_a 的地址為:\t" << int(d_a) << endl;
	cout << "d_b 的地址為:\t" << int(d_b) << endl;
}

輸出結果為:

g_a 的地址為:  5300224		g_b 的地址為:  5300228	
a 的地址為:    6421316		b 的地址為:    6421304
s_a 的地址為:  5300232		s_b 的地址為:  5300236
d_a 的地址為:  9547944		d_b 的地址為:  9547992

我們從中可以看到,g_ag_bs_as_b 都屬於全域性區,同理,ab 都屬於棧區,d_ad_b 都屬於堆區。由於棧區的資料在程式執行結束後會被編譯器自動銷燬,因此不要返回區域性變數的地址,舉例如下:

int* func()
{
	int a = 10;	// 棧區資料,在程式執行完之後自動釋放
	return &a;	//雖然返回了a的地址,然而資料在func結束時已經被銷燬
}

int main(void)
{
	int* a = func();	// 此時a表示在函式func在棧區開闢的地址,但是其中的資料已被銷燬
	cout << "a 的地址為:\t" << int(a) << "a 存放的資料為:\t" << *a << endl;
	cout << "a 的地址為:\t" << int(a) << "a 存放的資料為:\t" << *a << endl;
}

輸出結果為:

a 的地址為:    7601480a 存放的資料為: 10
a 的地址為:    7601480a 存放的資料為: 2084553696

由於編譯器會對棧區的資料做一次保留,因此第一條的 cout 語句能夠正常輸出,然而第二次的輸出才是記憶體地址 a 中的資料。

相反,堆區資料由程式設計師自己進行管理,在程式執行完之後並不會自動釋放。當整個程式執行完畢之後會由作業系統釋放。

int* func()
{
	int * a = new int(10);	// 棧區資料,在程式執行完之後自動釋放
	return a;	//雖然返回了a的地址,然而資料在func結束時已經被銷燬
}

int main(void)
{
	int* a = func();	// 此時a表示在函式func在棧區開闢的地址,但是其中的資料已被銷燬
	cout << "a 的地址為:\t" << int(a) << "a 存放的資料為:\t" << *a << endl;
	cout << "a 的地址為:\t" << int(a) << "a 存放的資料為:\t" << *a << endl;
}

輸出結果為:

a 的地址為:    23507016a 存放的資料為:        10
a 的地址為:    23507016a 存放的資料為:        10

相關文章