c++之引用及記憶體分割槽模型

奧拉弗洛斯基發表於2021-01-03

記憶體分割槽模型

c++程式執行時,將記憶體大放行劃分為4個區域

程式碼區:存放函式體的二進位制碼,由作業系統進行管理的
全域性區:存放全域性變數和靜態變數以及常量
棧區:由編譯器自動分配釋放,存放函式的引數值、區域性變數等
堆區:由程式設計師分配和釋放,若程式設計師不釋放,程式結束時由作業系統收回

在程式執行前
在程式編譯後,生成了exe可執行程式,未執行該程式前分為兩個區域

程式碼區:存放CPU執行的機器指令
特點:
程式碼區是共享的,共享的目的是對於頻繁被執行的程式,只需在記憶體中有一份程式碼即可
程式碼區是隻讀的,使其只讀的原因時防止程式意外的修改了它的指令

全域性區:全域性變數,靜態變數,常量(字串常量,全域性常量(用const修飾的全域性變數))
特點:
只要是用區域性修飾的(區域性變數、區域性常量)都不在全域性區
該區域的資料在程式結束後由作業系統釋放

程式執行後

棧區:由編譯器自動分配釋放,存放函式的引數值,區域性變數等
不要返回區域性變數的地址,因為棧區開闢的資料由編譯器自動釋放

一定要好好看看底下的程式碼,可以幫助理解記憶體分割槽模型!

#include<iostream>
using namespace std;
//棧區資料的注意事項
int* func()
{
	int a = 10;//區域性變數  存放在棧區,棧區的資料在函式執行完之後自動釋放,已經被釋放了所以就不能返回
	return &a;//返回區域性變數的地址
}
//在堆區開闢資料
int* func1()
{
	//利用new關鍵字,可以將資料開闢到堆區
	*//p這個指標的本質也是區域性變數,放在棧上,但指標儲存的資料是放在堆區的*
	int* p = new int(10);//(初始值)
	return p;//返回在堆區開闢空間的地址
}
int main()
{
	int* p = func();
	cout << *p << endl;//10  第一次可以列印正確是因為編譯器做了保留
	cout << *p << endl;//亂碼  第二次就不會保留了

	cout << endl;

	//堆區 由程式設計師分配釋放,若程式設計師不釋放,程式執行結束時有作業系統回收
	int* q = func1();
	
	cout << (int)q << endl;
	cout << (int)q << endl;

	cout << *q << endl;
	cout << *q << endl;

	system("pause");
	return 0;
}

引用

引用通俗易懂的來講就是給變數起一個別名,別名和原名代表同一塊記憶體,也就是可以通過操作別名間接的對原名操作,一般用在做函式引數。
引用的語法:
資料型別 & 引用名 = 原名

int a =10;
int &b = a;//b就是a的引用

注意事項:
1、引用時必須初始化
2、初始化後就不可更改(不可多次初始化)
引用的本質:
引用在c++內部實現是一個指標常量(指標的指向不可以改變,指標指向的值可以改變),這就是為什麼引用不可多次初始化。

int a = 10;
int &b = a;//等價於int * const b = &a;
b = 20;//等價於*b = 20;

引用的用途:
1、引用做函式引數
在函式傳參是,可以利用引用的技術使形參修飾實參,這可以簡化指標修改實參

//值傳遞
void myswap01(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;
	cout << "形參a = " << a << endl;
	cout << "形參b = " << b << endl;
}
//地址傳遞
void myswap02(int *a, int *b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}
//引用傳遞
void myswap03(int &a, int &b)
{

	int temp = a;
	a = b;
	b = temp;
	cout << "形參a = " << a << endl;
	cout << "形參b = " << b << endl;
}
void test()
{
	cout << "值傳遞" << endl;
	int a = 10;
	int b = 20;
	myswap01(a, b);
	cout << "實參a = " << a << endl;
	cout << "實參b = " << b << endl;
	cout << endl;

	myswap02(&a, &b);
	cout << "實參a = " << a << endl;
	cout << "實參b = " << b << endl;

	a = 10; b = 20;
	myswap03(a, b);//引用傳遞,形參也會修飾實參
	cout << "實參a = " << a << endl;
	cout << "實參b = " << b << endl;

}

通過測試我們可以發現引用傳遞和地址傳遞的效果是一樣的,但很明顯引用傳遞更簡單,c++推薦使用引用技術。
2、引用做函式返回值
引用是可以作為函式的返回值存在的
注意:不要返回區域性變數引用
用法:函式呼叫作為左值

#include<iostream>
using namespace std;
int& test01() 
{

	int a = 10;//存放在棧區
	return a;
}

int& test02()
{
	static int a = 10;//靜態變數,存放再全域性區
	return a;
}

int main()
{
	int& ref = test01();
	cout << "ref = " << ref<<endl;//第一次是對的,是因為編譯器做了保留
	cout << "ref = " << ref<<endl;//第一次執行後,a的記憶體已經釋放,所以會輸出亂碼

	int& ref1 = test02();
	cout << "ref1 = " << ref1 << endl;
	cout << "ref1 = " << ref1 << endl;

	test02() = 1000;//如果函式的返回值是引用,函式的呼叫可以作為左值(在這裡相當於對a進行賦值)
	cout << "ref1 = " << ref1 << endl;
	cout << "ref1 = " << ref1 << endl;//ref 是別名,可以訪問a的記憶體
	system("pause");
	return 0;
}

相關文章