C++:指針和引用

引用的概念及用法 
所謂的引用並非說從新定義的一個新的變量,而是給一個已經定義好了的變量起的一個別名。 
下面看看引用究竟是如何使用的:函數

void test1()
{
    int a = 1;
    int& b = a; //引用變量b是a的別名學習

    std::cout<<"a:address->"<<&a<<std::endl;
    std::cout<<"A:address->"<<&b<<std::endl;  //注意這裏的&是取地址指針

    a = 10;
    b = 100;
    std::cout<<"a = "<<a<<std::endl;
    std::cout<<"b = "<<b<<std::endl;對象

    int& c = b; //應用變量c是引用變量b的別名,別名的別名
    c = 1000;
    std::cout<<"a = "<<a<<std::endl;
    std::cout<<"b = "<<b<<std::endl;
    std::cout<<"c = "<<c<<std::endl;
}

運行結果以下: blog


 
由結果咱們能夠看出引用變m量b與變量a的地址是同樣的,該變b的值也會影響a。而且一個變量能夠取多個別名,這裏b是a的別名,c是b的別名,也就是a的別名了。就像咱們人同樣,你有一個大名(身份證上的名字),可能還會有一個小名,也或許還會給本身起一個洋氣的英文名,總之無論別人叫哪個名字,叫的都是你本人就對了。內存

總結: 
一、一個變量能夠有多個別名 
二、引用必須初始化b 
三、引用只能在初始化的時候引用一次,以後不能再引用其餘的變量作用域

引用作參數 
在以前的學習當中,咱們知道調用函數的傳參有傳值調用和傳址調用。下面再來看一看這兩種方式:test

一、傳值調用變量

void swap(int a,in b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
//如今的咱們都知道了這樣的函數是沒法完成咱們但願的交換功能的。
//究其緣由,就是由於這裏使用的是傳值方式,那麼若是別人一旦想要
//調用我給我傳兩個參數,我就要生成兩個局部的臨時變量用來接收
//別人給我傳的兩個參數。可是當調用結束,函數棧幀釋放,相應的
//用於接收參數的兩個局部變量也會被一同釋放掉,可是交換是發生在
//這兩個局部變量之間的,如今他們已經被釋放掉了,而且從頭至尾
//都沒有對調用方的兩個想要交換的變量產生任何影響。所以這裏的
//傳值調用並完成不了交換的功能。

二、傳址調用語法

void swap(int *a,int *b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
//所謂的傳址調用就是傳指針。
//如今咱們將兩個形參改成指針,也就是說別人想要調用我完成交換功能時
//就將想要交換的兩個變量的地址傳給我就行了。函數調用期間對地址裏面
//的內容進行交換,即使調用結束之後,函數棧幀被釋放,可是是對兩個地址
//的內容進行了交換,釋放棧幀之後這兩個地址並非函數棧幀裏的,
//因此並不會一併被釋放,而且完成了交換的功能。

三、傳引用

void swap(int& a,int& b)
{
    int tmp = a;
    a = b;
    b = tmp;
}
//咱們知道引用變量就是咱們給一個已經定義好的變量起的一個別名,
//因此說,若是咱們這裏採用傳引用的方式,那咱們這裏的形參就是實參的別名
//在剛剛咱們也看了,變量和變量的別名,他們兩個的地址是同一個,因此啊,
//這和傳址調用有着殊途同歸之妙。

引用作返回值

有時候咱們一個函數調用結束須要返回一些信息供調用方使用。好比說一個加法函數。

//方法一
int ADD(int a,int b)
{
    int ret = a+b;
    return ret;
}
//方法二
int& ADD(int a,int b)
{
    int ret = a+b;
    return ret;
}
//這裏方法一是採用值的形式返回,而方法2是採用引用的形式返回。
//咱們能夠看看彙編語言是如何這兩種不一樣返回方式的,以下圖:

 


 
那麼問題來了,咱們有該如何選擇以那種方式返回呢???

一、若是返回的對象出了該函數做用域依舊存在,則使用引用返回,由於這樣會更加高效 
二、若是返回對象處了函數的做用域就不存在了,則使用值返回。 
注意:不要返回一個臨時變量的引用,由於臨時變量在函數調用結束之後會隨着棧幀的釋放而被釋放,而傳引用返回的方式返回的是變量的地址,而事實是該變量已經被釋放。

引用和指針的區別 
在這以前咱們一直在說,引用是一個變量的別名,因此可能就會想到說這個引用變量時不會佔據任何的空間的。可是!請注意!這種想法是不對的。引用變量也是會佔據必定的內存空間的,也須要在棧上額外佔用存儲空間。 
由於引用的底層實現實際上是指針。從語法上來看只是一個別名,但在底層上依舊是開闢了一塊空間。

int main()
{
    int a = 0;
    int& b = a;
    return 0;
}

看一下這段代碼的彙編:是如何處理變量a,和引用變量b 


 
從彙編咱們能夠看出對引用變量初始化爲a的別名,就是將a的地址給了引用變量b。想想這種方式是否是很熟悉?對了,正如你所想到的咱們常常寫的一個代碼:

int a = 0;
int *p = &a;
//取a的地址賦給指針變量p

這樣看來其實引用的底層也就是一個指針,只不過明面上向咱們所展現的是一個變量的別名,但咱們應該注意引用變量是一個已經定義過的變量的別名,他是別名,他也佔空間,由於他的底層實現是指針。

下面就看一看引用和指針的區別:

一、引用只能在定義時初始化一次,以後不能改變指向其餘的變量,但指針能夠。  二、引用必須指向有效的變量,但指針能夠爲空。  三、sizeof引用獲得的是所指向的變量的大小,但sizeof指針是對象的地址的大小。  四、引用的自增(+ +)自減(- -)是對值的+1或-1,而指針++或–是+或-其所指向的類型大小。  

相關文章
相關標籤/搜索