1 內(nèi)存分區(qū)模型
C++程序在執(zhí)行時(shí)衩椒,將內(nèi)存大方向劃分為4個(gè)區(qū)域
- 代碼區(qū):存放函數(shù)體的二進(jìn)制代碼,由操作系統(tǒng)進(jìn)行管理的
- 全局區(qū):存放全局變量和靜態(tài)變量以及常量
- 棧區(qū):由編譯器自動(dòng)分配釋放, 存放函數(shù)的參數(shù)值,局部變量等
- 堆區(qū):由程序員分配和釋放,若程序員不釋放,程序結(jié)束時(shí)由操作系統(tǒng)回收
內(nèi)存四區(qū)意義:
不同區(qū)域存放的數(shù)據(jù)斟湃,賦予不同的生命周期, 給我們更大的靈活編程
1.1程序運(yùn)行前
在程序編譯后犬性,生成了exe可執(zhí)行程序父叙,未執(zhí)行該程序前分為兩個(gè)區(qū)域
?代碼區(qū):
?存放 CPU 執(zhí)行的機(jī)器指令
?代碼區(qū)是共享的,共享的目的是對(duì)于頻繁被執(zhí)行的程序讥裤,只需要在內(nèi)存中有一份代碼即可
?代碼區(qū)是只讀的,使其只讀的原因是防止程序意外地修改了它的指令
?全局區(qū):
?全局變量和靜態(tài)變量存放在此.
?全局區(qū)還包含了常量區(qū), 字符串常量和其他常量也存放在此.
?該區(qū)域的數(shù)據(jù)在程序結(jié)束后由操作系統(tǒng)釋放.
代碼示例:
'''
#include <iostream>
using namespace std;
//g-global l-local c-const s-static
//全局變量
int g_a = 10;
int g_b = 10;
//全局常量
const int c_g_a = 10;
const int c_g_b = 10;
int main() {
//局部變量
int a = 10;
int b = 10;
cout << "局部變量a地址為: " << (int)&a << endl;
cout << "局部變量b地址為: " << (int)&b << endl;
cout << "全局變量g_a地址為: " << (int)&g_a << endl;
cout << "全局變量g_b地址為: " << (int)&g_b << endl;
//靜態(tài)變量
static int s_a = 10;
static int s_b = 10;
cout << "靜態(tài)變量s_a地址為: " << (int)&s_a << endl;
cout << "靜態(tài)變量s_b地址為: " << (int)&s_b << endl;
//字符串常量"xxxx"
cout << "字符串常量地址為: " << (int)&"hello world" << endl;
cout << "字符串常量地址為: " << (int)&"hello world1" << endl;
cout << "全局常量c_g_a地址為: " << (int)&c_g_a << endl;
cout << "全局常量c_g_b地址為: " << (int)&c_g_b << endl;
//const修飾的變量(局部常量)
const int c_l_a = 10;
const int c_l_b = 10;
cout << "局部常量c_l_a地址為: " << (int)&c_l_a << endl;
cout << "局部常量c_l_b地址為: " << (int)&c_l_b << endl;
system("pause");
return 0;
}
'''
總結(jié):
- C++中在程序運(yùn)行前分為全局區(qū)和代碼區(qū)
- 代碼區(qū)特點(diǎn)是共享和只讀
- 全局區(qū)中存放全局變量姻报、靜態(tài)變量坞琴、常量
- 常量區(qū)中存放 const修飾的全局常量 和 字符串常量
1.2程序運(yùn)行后
棧區(qū):
?由編譯器自動(dòng)分配釋放, 存放函數(shù)的參數(shù)值,局部變量等
?注意事項(xiàng):不要返回局部變量的地址,棧區(qū)開辟的數(shù)據(jù)由編譯器自動(dòng)釋放
代碼示例:
'''
#include <iostream>
using namespace std;
//棧區(qū)的數(shù)據(jù)存儲(chǔ)空間由編譯器開辟和釋放
//棧區(qū)中注意不要返回局部變量的地址
int* func()
{
int a = 10;//在函數(shù)調(diào)用結(jié)束后釋放內(nèi)存空間
return &a;
}
int main() {
//接受返回的地址
int* p = func();
cout << *p << endl;//第一次輸出正確逗抑,編譯器做了保留
cout << *p << endl;//第二次輸出錯(cuò)誤剧辐,不再做保留
system("pause");
return 0;
}
'''
輸出結(jié)果:
10
-858993460
堆區(qū):
?由程序員分配釋放,若程序員不釋放,程序結(jié)束時(shí)由操作系統(tǒng)回收
?在C++中主要利用new在堆區(qū)開辟內(nèi)存
代碼示例:
'''
#include <iostream>
using namespace std;
//堆區(qū)由程序員分配釋放,若程序員不釋放,程序結(jié)束時(shí)由操作系統(tǒng)回收
int* func()
{
int* a = new int(10);//可以使用new關(guān)鍵字開辟堆區(qū)空間
return a;
//指針a本質(zhì)也是存放在棧區(qū)的局部變量,但是數(shù)據(jù)是存放在堆區(qū)邮府,函數(shù)調(diào)用結(jié)束不會(huì)被釋放
}
int main() {
//接受地址荧关,存放指針a的內(nèi)存已經(jīng)被釋放,但是這個(gè)地址指向的存放在堆區(qū)的數(shù)據(jù)還在
int* p = func();
cout << *p << endl;
cout << *p << endl;
system("pause");
return 0;
}
'''
輸出結(jié)果
10
10
總結(jié):
堆區(qū)數(shù)據(jù)由程序員管理開辟和釋放
堆區(qū)數(shù)據(jù)利用new關(guān)鍵字進(jìn)行開辟內(nèi)存
1.3new操作符
C++中利用new操作符在堆區(qū)開辟數(shù)據(jù)
? 堆區(qū)開辟的數(shù)據(jù)褂傀,由程序員手動(dòng)開辟忍啤,手動(dòng)釋放,釋放利用操作符 delete
? 語(yǔ)法:new 數(shù)據(jù)類型
? 利用new創(chuàng)建的數(shù)據(jù)仙辟,會(huì)返回該數(shù)據(jù)對(duì)應(yīng)的類型的指針
示例1: 基本語(yǔ)法
```
#include <iostream>
using namespace std;
int* func()
{
int* a = new int(10);
return a;
}
int main()
{
int *p = func();
cout << *p << endl;
cout << *p << endl;
//利用delete釋放堆區(qū)數(shù)據(jù)
delete p;
//cout << *p << endl; //報(bào)錯(cuò)同波,釋放的空間不可訪問
system("pause");
return 0;
}
```
輸出:
10
10
示例2:開辟數(shù)組
```
#include <iostream>
using namespace std;
//堆區(qū)開辟數(shù)組
int main()
{
//new返回?cái)?shù)值的首地址
int* arr = new int[10];
for (int i = 0; i < 10; i++)
{
arr[i] = i + 1;
}
for (int i = 0; i < 10; i++)
{
cout << arr[i] << " ";
}
//釋放數(shù)組 delete 后加 []
delete[] arr;//表明你釋放的是一段空間
system("pause");
return 0;
}
```
輸出:
1 2 3 4 5 6 7 8 9 10