C++內存四大區域

捕獲一只小肚皮 2021-08-15 04:44:40 阅读数:753

本文一共[544]字,预计阅读时长:1分钟~
c++ 四大

前言

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;
}
image-20210814194627826

我們可以清晰的發現全局變量的地址都是很接近的.


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;
}
屏幕截圖 2021-08-14 195224

我們發現靜態變量與全局變量的地址都是非常接近的,原因就是他們都存在全局區域


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;
}
屏幕截圖 2021-08-14 195224

我們仍然可以清晰的看到全局變量的地址都是在一定的區域段的(不要說相同段只有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;
}
image-20210814211600366

可以發現局部變量前面區段的地址和全局變量差距特別大,這就很好的說明了全局區棧區是兩個不同區域


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;
}
image-20210814212849588

可以發現全局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;
}
image-20210814214301080

咦???,博主被打臉了哎,怎麼還是可以訪問到值呢?並且是正確的10

真的是這樣嗎?我們再調用幾次試試?

image-20210814214623302

發現是不是只有第一次調用才是正確的?其實之所以第一次調用對了,是因為編譯器(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;
}
image-20210814215402212

我們發現堆區就完全不受影響,其值仍然是堆區的值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;
}
image-20210814221524148

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;
}
image-20210814222734005
版权声明:本文为[捕獲一只小肚皮]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815044425679L.html