文章目錄
- 前言
- 所劃分的記憶體區塊有?
- 代碼區決議
- 全域區決議
- 1 全域變數的地址
- 2 靜態變數的地址
- 3 常量(字符常量及const全域常量)
- 堆疊區決議
- 1 普通區域變數
- 2 const修飾區域變數
- 3 堆疊區注意事項
- 堆區決議
- new的用法
- 1 開辟單個堆區元素
- 2 開辟陣列
前言
c++在執行程式(
.exe程式)時候會對記憶體進行劃磁區域,主要目的就是方便更加高效以及靈活編程.那么,在此程序階段,是怎樣劃磁區域,以及各區域都是在發揮著什么作用呢? 下面博主就詳細的給大家介紹介紹
所劃分的記憶體區塊有?
在執行C++程式時候,所劃分出的記憶體區塊主要有四個:
代碼區:存放著程式的二進制代碼,由作業系統管理全域區:存放全域變數,靜態變數,以及常量(字符常量和const修飾的全域變數)堆疊區:存放所有的區域變數,其空間分配釋放由編譯器管理,當函式結束,區域變數自動被釋放堆區:存放所有動態開辟的變數,其空間分配釋放由程式員管理
其中在exe程式執行前只有代碼區和全域區,在執行時才具有堆疊區與堆區
代碼區決議
在代碼區里面存放的是
exe二進制機器指令,它(代碼區)具有兩個特性:
共享性:即在記憶體里面只有一份此程式代碼,而無論誰都可以使用并運行它. 好處是當被頻繁使用時,節約更多空間只讀性:即不允許被修改,這個很好理解.比如我們玩的王者游戲,官方設定一套皮膚100元,而當你下載此游戲并運行時候,有人給你修改了,變成一套皮膚1000元,你干嗎?
全域區決議
全域區存的是全域變數,靜態變數,以及常量,下面博主便演示下:
1 全域變數的地址
我們先定義幾個全域變數,然后進行輸出:
#include <iostream>
using namespace std;
int ga = 10; //g是global(全域)的意思
int gb = 20;
int gc = 20;
int main()
{
cout<<"全域變數ga的地址是"<<&ga<<endl;
cout<<"全域變數gb的地址是"<<&gb<<endl;
cout<<"全域變數gc的地址是"<<&gc<<endl;
return 0;
}
我們可以清晰的發現全域變數的地址都是很接近的.
2 靜態變數的地址
我們定義幾個靜態變數,然后輸出地址:
#include <iostream>
using namespace std;
int ga = 10; //g是global(全域)的意思
int gb = 20;
int gc = 20;
int main()
{
static int sa = 10;
static int sb = 20;
static int sc = 20;
cout << "全域變數ga的地址是" << &ga << endl;
cout << "全域變數gb的地址是" << &gb << endl;
cout << "全域變數gc的地址是" << &gc << endl;
cout << "靜態變數sa的地址是" << &sa << endl;
cout << "靜態變數sb的地址是" << &sb << endl;
cout << "靜態變數sc的地址是" << &sc << endl;
return 0;
}
我們發現靜態變數與全域變數的地址都是非常接近的,原因就是他們都存在全域區域
3 常量(字符常量及const全域常量)
一樣的道理,首先創建常量,然后輸出地址
#include <iostream>
using namespace std;
int ga = 10; //g是global(全域)的意思
int gb = 20;
int gc = 20;
const int cga = 10; //c是const
const int cgb = 10;
const int cgc = 10;
int main()
{
static int sa = 10;
static int sb = 20;
static int sc = 20;
cout << "全域變數ga的地址是" << &ga << endl;
cout << "全域變數gb的地址是" << &gb << endl;
cout << "全域變數gc的地址是" << &gc << endl;
cout << endl;
cout << "靜態變數sa的地址是" << &sa << endl;
cout << "靜態變數sb的地址是" << &sb << endl;
cout << "靜態變數sc的地址是" << &sc << endl;
cout << endl;
cout << "字符常量1的地址是" << &"123"<<endl;
cout << "字符常量1的地址是" << &"124"<<endl;
cout << "字符常量1的地址是" << &"125"<<endl;
cout << endl;
cout << "const修飾的全域變數cga地址是" << &cga<<endl;
cout << "const修飾的全域變數cgb地址是" << &cgb<<endl;
cout << "const修飾的全域變數cgc地址是" << &cgc<<endl;
return 0;
}
我們仍然可以清晰的看到全域變數的地址都是在一定的區域段的(不要說相同段只有005B哦,這是16進制,換算成10進制,這個區段很大的)
堆疊區決議
堆疊區存放的是區域變數,現在我們用一些全域變數和區域變數進行比較
1 普通區域變數
#include <iostream>
using namespace std;
int ga = 10; //g是global(全域)的意思
int gb = 20;
int gc = 20;
int main()
{
int la = 10; //l是local(區域的意思)
int lb = 20;
int lc = 20;
cout << "全域變數ga的地址是" << &ga << endl;
cout << "全域變數gb的地址是" << &gb << endl;
cout << "全域變數gc的地址是" << &gc << endl;
cout << endl;
cout << "區域變數la的地址是" << &la << endl;
cout << "區域變數lb的地址是" << &lb << endl;
cout << "區域變數lc的地址是" << &lc << endl;
return 0;
}
可以發現區域變數前面區段的地址和全域變數差距特別大,這就很好的說明了全域區和堆疊區是兩個不同區域
2 const修飾區域變數
我們用全域變數,全域const,區域變數,區域const進行對比
#include <iostream>
using namespace std;
int ga = 10; //g是global(全域)的意思
int gb = 20;
int gc = 20;
const int cga = 10; //c是const
const int cgb = 10;
const int cgc = 10;
int main()
{
int a = 10;
int b = 10;
int c = 10;
const int ca = 10;
const int cb = 20;
const int cc = 30;
cout << "全域變數ga的地址是" << &ga << endl;
cout << "全域變數gb的地址是" << &gb << endl;
cout << "全域變數gc的地址是" << &gc << endl;
cout << endl;
cout << "const修飾的全域變數cga地址是(全域常量)" << &cga << endl;
cout << "const修飾的全域變數cgb地址是(全域常量)" << &cgb << endl;
cout << "const修飾的全域變數cgc地址是(全域常量)" << &cgc << endl;
cout << endl;
cout << "區域變數a的地址是" << &a << endl;
cout << "區域變數b的地址是" << &b << endl;
cout << "區域變數c的地址是" << &c << endl;
cout << endl;
cout << "const修飾的區域變數ca的地址是(區域常量)" << &ca << endl;
cout << "const修飾的區域變數cb的地址是(區域常量)" << &cb << endl;
cout << "const修飾的區域變數cc的地址是(區域常量)" << &cc << endl;
return 0;
}
可以發現全域const常量和區域const常量他們的所屬區是不一樣的,區域const常量是所屬于堆疊區.
3 堆疊區注意事項
堆疊區里面的變數不可回傳地址,因為在func函式結束時候a的空間就被釋放了,里面存的值就沒有了,不信我們看下面:
#include <iostream>
using namespace std;
int* func()
{
int a = 10;
return &a;
}
int main()
{
int* p = func();
cout<<"*p的值是"<<endl;
return 0;
}
咦???,博主被打臉了哎,怎么還是可以訪問到值呢?并且是正確的10
真的是這樣嗎?我們再呼叫幾次試試?
發現是不是只有第一次呼叫才是正確的?其實之所以第一次呼叫對了,是因為編譯器(VS2019)害怕你誤用,特地給你保留了一次結果,哎~~,編譯器為了我們這些憨憨可真是操碎了心.
堆區決議
堆區的開辟釋放由程式員自己執行,開辟一般用
new,釋放一般用delete
#include <iostream>
using namespace std;
int* func()
{
int* p = new int(10); //看不懂這里的,下面有介紹new用法
return p;
}
int main()
{
int* p = func();
cout<<"func的值是"<<*p<<endl;
cout<<"func的值是"<<*p<<endl;
cout<<"func的值是"<<*p<<endl;
delete p;
return 0;
}
我們發現堆區就完全不受影響,其值仍然是堆區的值10
new的用法
1 開辟單個堆區元素
語法:
- 開辟:
type* name = new type(content);type是元素型別,content是元素內容,name是變數名- 釋放:
delete name
#include <iostream>
using namespace std;
int main()
{
int* p1 = new int(10); //開辟整型元素,存10進去
float* p2 = new float(20.12); //開辟單精度浮點,存20.12進去
char* p3 = new char('w'); //開辟字符元素,存'w'進去
cout << "整型元素的值是" << *p1 <<endl;
cout << "浮點元素的值是" << *p2 <<endl;
cout << "字符元素的值是" << *p3 <<endl;
delete p1;
delete p2;
delete p3;
return 0;
}
2 開辟陣列
語法:
type* name = new type[size];name是變數名,type是型別,size是陣列空間數量- 釋放:
delete []name必須有一個[ ]哦~~~
#include <iostream>
using namespace std;
int main()
{
int* p1 = new int[10]; //開辟整型陣列,10個元素
char* p2 = new char[10]; //開辟字符陣列,10個元素
for (int i = 0; i < 10; i++) //整形陣列賦值
p1[i] = i + 10;
for (int i = 0; i < 10; i++)//字符陣列賦值
p2[i] = i + 65;
for (int i = 0; i < 10; i++) //列印
cout << p1[i] << ' ';
cout << endl;
for (int i = 0; i < 10; i++)
cout << p2[i] << ' ';
delete []p1;
delete []p2;
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/294018.html
標籤:其他
