C++階段總結第二部分

第二部分 C++核心編程一

目錄

第二部分 C++核心編程一

1,內存分區模型

1.1程序運行前

1.2程序運行後

1.2new操作符

2.引用

2.1引用的基本使用

2.2注意事項

2.3引用做函數參數

2.4引用做函數返回值

2.5引用的本質

2.6常量引用

3,函數的提高

3.1函數的默認參數

3.2函數佔位參數

3.3函數重載


1,內存分區模型

C++在程序執行時,將內存大方向劃分爲4個區域

  • 代碼區:存放函數體的二進制代碼,由操作系統進行管理的
  • 全局區:存放全局變量和靜態變量以及常量
  • 棧區:由編譯器自動分配釋放,存放函數的參數值,局部變量等
  • 堆區:由程序員分配和釋放,若程序員不釋放,程序結束時由操作系統回收

劃分的意義:不同區域存放的數據,賦予不同的生命週期,給我們更大的靈活編程

1.1程序運行前

未執行該程序前分爲兩部分

代碼區:

    存放CPU執行的機器指令

     代碼區是共享的,共享的目的是對於頻繁被執行的程序,只需要在內存中有一份代碼即可(.exe文件每次執行都是這一段代碼)

     代碼區是只讀的,使其只讀的原因是防止程序意外地修改了他的指令  (.exe文件不能被修改)

全局區:

      全局變量和靜態變量存放在此

      全局區還包括了常量區,字符串常量和其它變量也存放在此(常量區包括:const修飾的全局常量和字符串常量)

      該區域的數據在程序結束後由操作系統釋放(只要是局部定義的都不在全局區,不論是字符串還是字符)

如下一段程序代碼運行結果:

#include<iostream>
#include<string>
using namespace std;

int aa = 10;
int bb = 11;

const int c_a_1 = 10;
const int c_b_1 = 10;

int main()
{
	int a = 10;
	int b = 11;

	static int a_1 = 10;
	static int b_1 = 10;

	string a_2 = "dasfaf";
	string b_2 = "hjkjhh";

	const int c_a_2 = 10;
	const int c_b_2 = 10;

	cout << "局部a=" << (int)&a << endl;
	cout << "局部b=" << (int)&b << endl << endl;

	cout << "全局aa=" << (int)&aa << endl;
	cout << "全局bb=" << (int)&bb << endl << endl;
	
	cout << "靜態a_1=" << (int)&a_1 << endl;
	cout << "靜態b_1=" << (int)&b_1 << endl << endl;

	cout << "常字符串=" << (int)&"adssasdf" << endl;
	cout << "常字符串=" << (int)&"dsaassaa" << endl << endl;

	cout << "局部字符串a_2=" << (int)&a_2 << endl;
	cout << "局部字符串b_2=" << (int)&b_2 << endl << endl;

	cout << "全常c_a_1=" << (int)&c_a_1 << endl;
	cout << "全常c_b_1=" << (int)&c_b_1 << endl << endl;

	cout << "局常c_a_2=" << (int)&c_a_2 << endl;
	cout << "局常c_b_2=" << (int)&c_b_2 << endl << endl;
	system("pause");
	return 0;
}

1.2程序運行後

棧區:由編譯器自動分配釋放,存放函數的參數值,局部變量等

注:不要返回局部變量的地址,棧區開闢的數據由編譯器自動釋放,所以當自定義函數使用過後,局部變量就會被自動釋放

int *ap(int a)
{
    a = 1;
    int b = 2;        //局部變量,放在棧上,函數執行,棧區的數據就被釋放了
    return &a(或者return &b);        //返回局部變量地址,只能保留一次該數據
}

此時不論返回a的地址還是b的地址,都會出錯,因爲形參也是局部變量,所以當這個函數運行過後,都會被自動釋放。

#include<iostream>
#include<string>
using namespace std;

int b = 1;
int *ap()
{
	int a = 1;        //局部變量,放在棧上,函數執行完,棧區的數據就被釋放了
	return &a;        //返回局部變量地址
}

int *aq()
{
	return &b;        //返回全局變量地址
}

int main()
{
	int *p = ap();
	cout << "p=" << *p << endl;      //第一次可以打印正確數據,編譯器做了保存
	cout << "p=" << *p << endl;      //第二次這個數據就不被保存了
	
	int *q = aq();
	cout << "q=" << *q << endl;      //因爲返回的是全局變量的地址,所以不會被自動釋放,只有程序結束後纔會被釋放
	cout << "q=" << *q << endl;      
	
	system("pause");
	return 0;
}

堆區:由程序員分配釋放,如果程序員不釋放,則程序結束時由操作系統回收

在C++中主要利用new在堆區開闢內存

指針本質上也是局部變量,放在棧上,指針保存的數據是放在堆區

int *ap()
{
    int *b = new int;        //定義堆區數據
    *b = 10;
    return b;        堆區的數據不會被釋放
}

1.2new操作符

C++中利用new操作符在堆區開闢數據

堆區開闢的數據,由程序員手動開始,手動釋放,釋放利用操作符delete

語法:new 數據類型

利用new創建的數據,會返回該數據對應的類型的指針

    int *p = new int(10);     //堆區開闢一個數據
    delete p;       //釋放該數據

    int *q = new int[10];     //堆區開闢一個數組
    delete[] q;     //釋放該數組

2.引用

2.1引用的基本使用

作用:給變量起別名(兩個變量的地址一樣)

語法:數據類型 &別名=原名

    int a = 10;
    int &b = a;

2.2注意事項

  • 引用必須初始化
  • 引用在初始化後,不可改變

    int a = 10, aa = 20;
    int &b = a;
    int &c; //錯誤,引用必須初始化
    &b = aa;//錯誤,初始化後,不可改變
    b = aa;//賦值操作

2.3引用做函數參數

作用:函數傳參時,可以利用引用的技術讓形參修飾實參

優點:可以簡化指針修改實參(可以參照值傳遞地址傳遞

void swap(int &a, int &b)         //引用傳遞交換兩數的值
{
    int x = a;
    a = b;
    b = x;
}

#include<iostream>
#include<string>
using namespace std;

void swap(int &a, int &b)
{
	int x = a;
	a = b;
	b = x;
}

int main()
{
	int a = 10, b = 20;
	swap(a, b);
	cout << a << "  " << b << endl;
	system("pause");
	return 0;
}

2.4引用做函數返回值

作用:引用是可以作爲函數的返回值存在的

注意:不要返回局部變量的引用(和不要返回局部變量地址類似)

用法:函數調用作爲左值

int &test1() 
{
    int a = 10;       //錯誤,局部變量,系統只保存一次
    return a;
}

int &test2()
{
    static int b = 10;    //正確,全局變量
    return b;
}

特殊賦值方法,因爲函數返回的是一個引用,所以仍然可以賦值:eg:test2() = 111;

2.5引用的本質

引用的本質在C++內部實現是一個指針常量

    int &a = b;     //轉換爲 int *const a=&b;
    a = 10;         //轉換爲 *a=10;

2.6常量引用

作用:常量引用主要用來修飾形參,防止誤操作

在函數形參列表中,可以用const修飾形參,防止形參改變實參

    const int &a = 10;    //轉換爲int b=10; const int &a=b;

const使用場景,在當作形參時使用,防止數據被誤操作

void show(const int &a)
{
    //a = 20;    //錯誤,因爲傳遞時爲const所以不能改變
    cout << a << endl;
}

#include<iostream>
#include<string>
using namespace std;

void show(const int &a)
{
	//a = 20;    //錯誤,因爲傳遞時爲const所以不能改變
	cout << a << endl;
}

int main()
{
	int a=10;
	show(a);
	system("pause");
	return 0;
}

3,函數的提高

3.1函數的默認參數

在C++中,函數的形參列表中的形參可以是有默認值的

語法:返回值類型 函數名(參數=默認值){}

int test(int a = 1, int b = 2, int c = 3)
{
    return a + b + c;
}

注1:如果某個位置已經有了默認值,那麼從這個位置往後,從左到右都必須有默認值
int test(int a = 1, int b, int c)       //錯誤

注2:如果函數聲明有默認參數,函數實現就不能有默認參數‘(聲明和實現只能有一個默認參數)

int test(int a = 1, int b = 2, int c = 3);
int test(int a = 1, int b = 2, int c = 3)        //錯誤,聲明時,函數已經有參數了,所以實現不能有參數
{
    return a + b + c;
}

3.2函數佔位參數

C++中函數的形參列表裏可以有佔位參數,用來佔位,調用函數時必須填補該位置

語法:返回值類型 函數名(數據類型){}

void test1(int a, int)
{
    cout << "佔位參數" << endl;
}

3.3函數重載

作用:函數名可以相同,提高複用率

滿足條件:

  • 同一個作用域下
  • 函數名稱相同
  • 函數參數不同或者個數或者順序不同

返回值類型不可以作爲函數重載的條件

我的另一篇關於重載的博客鏈接:https://blog.csdn.net/qq_46423166/article/details/106594280

函數重載的注意事項

  • 引用作爲重載條件
  • 函數重載碰到函數默認參數

void test(int &a)
void test(const int &a)   //這兩個可以構成重載

void test(int a)
void test(int a, int b = 10)    //因爲包含默認參數,所以不能構成重載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章