C++ - 指針

指針

在了解什么是指針之前柜思,我們需要先搞清楚數(shù)據(jù)在內(nèi)存中是如何存儲的房维,又是如何讀取的傻粘。

如果在程序中定義一個變量每窖,在編譯的時候就給這個變量分配內(nèi)存單元。系統(tǒng)根據(jù)程序中定義的變量類型弦悉,會分配一定長度的空間窒典。例如:C++編譯系統(tǒng)一般為整型變量分配4個字節(jié),對單精度浮點型變量分配4個字節(jié)稽莉,對字符型變量分配1個字節(jié)瀑志。內(nèi)存區(qū)的每一個字節(jié)都有一個編號,這就是地址污秆,它可以類比我們旅館中的房間號劈猪,在地址所標識的內(nèi)存單元中存放數(shù)據(jù),這相當于旅館中各個房間中居住旅客一樣良拼。

注意:地址和內(nèi)容(值)是兩個概念战得,如下圖:

屏幕快照 2018-08-15 下午10.50.40.png

可以看到程序已定義了變量i,j,k,編譯的時候系統(tǒng)分配2000-2003這4個字節(jié)給變量i庸推,分配2004-2007這4個字節(jié)給j常侦,分配2008-2009給變量k。在程序中我們一般是通過變量名來對內(nèi)存單元進行存取操作贬媒,其實程序在經(jīng)過編譯以后已經(jīng)將變量名轉(zhuǎn)換為變量的地址聋亡,對變量值的存取都是通過地址進行的。

當我們執(zhí)行cout<<i;語句的時候际乘,即獲取變量i的值坡倔,根據(jù)變量名與地址的對應(yīng)關(guān)系(在編譯的時候確定),找到變量i的地址2000脖含,然后從2000開始的4個字節(jié)中取出數(shù)據(jù)罪塔,即變量的值為3,并輸出养葵。

當我們執(zhí)行cin>>i;語句的時候垢袱,即變量i賦值的時候,在執(zhí)行的時候港柜,就把值送到地址為2000開始的整型存儲單元中请契。如果執(zhí)行語句k=i+j;那么從2000字節(jié)開始的整型變量存儲單元中取出i的值3咳榜,從2004字節(jié)開始的變量存儲單元中取出j的值6,將它們進行相加爽锥,結(jié)果9送到k所占用的2008字節(jié)開始的整型存儲單元中涌韩。

上面的這種按變量地址存儲變量值的方式稱為直接存取方式。我們還可以使用另外一種存儲方法氯夷,間接存取方式臣樱,即將變量i的地址存放到另一個變量中

看到這里腮考,那么什么是指針呢雇毫?

其實地址就是指針,一個變量的地址稱為該變量的指針踩蔚。因為通過地址能找變量單元棚放,因此可以說,地址指向該變量單元馅闽。所以將地址形象化地稱為“指針”飘蚯,意思是通過它能找到以它為地址的內(nèi)存單元。

變量與指針

變量的指針其實就是變量的地址福也,用來存放變量地址的變量是指針變量局骤。有沒有感覺有點繞,嘿嘿暴凑。指針變量是一種特殊的變量峦甩,用它來指向另外一個變量,“*”表示指向现喳,比如:pointer是一個指針變量穴店,而*pointer表示pointer所指向的變量,也就是說*pointer也代表一個變量拿穴。

4010043-a193516f8303841c.png

定義指針變量

定義指針變量的形式:基類型 *指針變量名;

C++規(guī)定所有變量在使用前必須先定義忧风,即指定其類型默色。在編譯時按變量類型分配存儲空間。在Visual C++中狮腿,為每個指針變量分配4個字節(jié)的存儲空間腿宰。對指針變量必須定義為指針類型,如:

int i,j;  //定義整型的變量i,j
int *pointer1,*pointer2; //定義指針變量pointer1,pointer2

第二行開頭的int是指:所定義的指針變量是指向整型數(shù)據(jù)的指針變量缘厢,或者說pointer1和pointer2只能存儲整型數(shù)據(jù)的地址吃度,而不能存放其他數(shù)據(jù)類型的地址。

正如上面代碼所示贴硫,pointer1和pointer2可以指向整型數(shù)據(jù)i和j椿每,而不能指向浮點數(shù)伊者。int是指針變量的基類型,所謂基類型就是該指針變量指向的變量的類型间护。

注意:變量名是pointer1和pointer2而不是*pointer1和*pointer2亦渗,*表示該變量為指針變量

那么怎樣使一個指針變量指向另一個變量呢?簡單汁尺,只需要把被指向的變量的地址賦給指針變量即可法精。

pointer1 = &i; // 表示將變量i的地址存放到指針變量pointer1中
pointer2 = &j; // 表示將變量j的地址存放到指針變量pointer2中

通過上面賦值操作,pointer1指向了變量i痴突,pointer2指向了變量j搂蜓。

定義變量時注意幾點:

1、在定義指針變量時必須指定基類型

我們知道辽装,不同類型的數(shù)據(jù)在計算機系統(tǒng)中的存儲方式和所占的字節(jié)數(shù)是不相同的帮碰。因此,如果想通過指針引用一個變量如迟,只知道地址(如:2000)是不夠的收毫,因為無法判斷是從地址為2000的一個字節(jié)取出字符數(shù)據(jù),還是從2000-2003四個字節(jié)中取出int型數(shù)據(jù)殷勘,所以必須知道其類型此再,只有知道了數(shù)據(jù)類型,才能按存儲單元的長度以及數(shù)據(jù)的存儲形式正確的讀取數(shù)據(jù)玲销。

其實一個變量的指針包括兩個方面的含有:

  • 一是以存儲單元編號表示的地址(如:2000)
  • 一是它指向的存儲單元的數(shù)據(jù)類型(如:int输拇,float等),即基類型

2贤斜、怎么表示指針類型

比如:指向整型數(shù)據(jù)的指針類型表示為int *策吠,讀作指向int的指針

3、一個指針變量只能指向同一個類型的變量瘩绒,不能一會指向整型變量猴抹,一會指向單精度變量

引用指針變量

與指針變量相關(guān)的運算符:

1)&:取地址運算符
2)*:指針運算符(或稱間接訪問運算符)

如:&a表示變量a的地址,*p表示變量p所指向的存儲單元

例:通過指針變量訪問整型變量

int main(int argc, char const *argv[])
{
  int a,b; // 定義整型變量a,b
  int *pointer1, *pointer2; // 定義pointer1,pointer2為(int *)型變量锁荔,即指向整型數(shù)據(jù)的指針變量
  a = 100; b = 200; // 對a,b賦值

  pointer1 = &a; // 把變量a的地址賦給pointer1
  pointer2 = &b; // 把變量b的地址賦給pointer2

  cout<<a<<" "<<b<<endl; // 輸出a,b的值
  cout<<*pointer1<<" "<<*pointer2<<endl; // 輸出*pointer1和*pointer2的值
}

結(jié)果:

100 200
100 200

&和*運算符說明:

1蟀给、如果已經(jīng)執(zhí)行了“pointer1 = &a;”語句,那么&*pointer1的含義是什么阳堕?

&和*兩個運算符的優(yōu)先級別相同跋理,是按照自右而左的方向結(jié)合,因此先進行*pointer1運算恬总,那么結(jié)果就是變量a前普,然后再執(zhí)行&運算,即取變量a的地址壹堰。因此&*pointer1與&a相同拭卿,都是變量a的地址骡湖。

2、*&a的含義是什么记劈?

先進行&a運算勺鸦,得到a的地址,再進行*運算目木,即&a所指向的變量换途。所以*&a和*pointer1的作用一樣,都等價于變量a.

例:輸入a和b兩個整數(shù)刽射,按先大后小的順序輸出a和b(用指針變量處理)

int main(int argc, char const *argv[])
{
  int *p1, *p2, *p, a, b;
  cout<<"請輸入兩個整數(shù):"<<endl;
  cin>>a>>b;
  p1 = &a;
  p2 = &b;
  if (a<b) // 如果a小于b军拟,將p1的指向和p2的指向進行交互
  {
    p = p1;
    p1 = p2;
    p2 = p;
  }
  cout<<"a= "<<a<<" b= "<<b<<endl;
  cout<<"max= "<<*p1<<" min= "<<*p2<<endl;
}

運行結(jié)果:

請輸入兩個整數(shù):
10 15
a= 10 b= 15
max= 15 min= 10

注意一點:交互的是指針的指向,但是原來的值并未發(fā)生改變誓禁。p1的值原為&a懈息,p2的值為&b,在交互指向之后摹恰,p1指向了&b辫继,p2指向了&a,所以在使用*p1的時候取的是b的值俗慈,*p2取的是a的值姑宽。

用指針做函數(shù)參數(shù)

函數(shù)的參數(shù)不僅僅可以是整型、浮點型闺阱、字符型炮车,還可以是指針類型,它的作用是將一個變量的地址傳遞給被調(diào)用函數(shù)的形參酣溃。

例:同樣是上面的例子瘦穆,輸入兩個整數(shù)按大小輸出

int main(int argc, char const *argv[])
{
  void swap(int *p1, int *p2); // 函數(shù)聲明
  int *p1, *p2, a, b;
  cout<<"請輸入兩個整數(shù):"<<endl;
  cin>>a>>b;
  p1 = &a;
  p2 = &b;
  if (a<b) swap(p1, p2);
  cout<<"a= "<<a<<" b= "<<b<<endl;
  cout<<"max= "<<*p1<<" min= "<<*p2<<endl;
}

void swap(int *p1, int *p2) // 交換指針指向地址的值
{
  int temp;
  temp = *p1;
  *p1 = *p2;
  *p2 = temp;
}

運行結(jié)果:

請輸入兩個整數(shù):
10 15
a= 15 b= 10
max= 15 min= 10

可以看到a和b的值互換了,因為當使用指針做為參數(shù)的時候赊豌,傳遞的是地址扛或,然后在swap函數(shù)中我們將地址里面的值進行了互換,所以a,b的值進行了交換碘饼。

數(shù)組與指針

指向數(shù)組元素的指針

一個變量有地址熙兔,一個數(shù)組包含若干個元素,每個數(shù)組元素都在內(nèi)存中占用存儲單元派昧,它們都有相應(yīng)的地址,指針變量既然可以指向變量拢切,當然也可以指向數(shù)組元素蒂萎。即把某個元素的地址放到一個指針變量中。所謂數(shù)組元素的指針就是數(shù)組元素的地址淮椰。

在C和C++中五慈,數(shù)組名代表數(shù)組中第一個元素(即序號為0的元素)的地址纳寂。如:

int a[10];
int *p;
p = &a[0]; // 將元素a[0]的地址賦給指針變量p
p = a; // 同上

注意:數(shù)組名不代表整個數(shù)組,上面p=a;的作用是把a數(shù)組的首元素的地址賦給指針變量p泻拦,而不是把數(shù)組a各元素的值賦給p.

一旦將數(shù)組元素的首地址賦值給指針毙芜,那么我們可以通過指針來操作數(shù)組元素。如:

*p = 1;
*(p+1) = 2;
*(p+2) = 3;
p[3] = 4;
cout<<a[0]<<" "<<*p<<endl; //1 1
cout<<a[1]<<" "<<*(p+1)<<" "<<*(a+1)<<endl; // 2 2 2
cout<<a[2]<<endl; // 3
cout<<a[3]<<" "<<*(p+3)<<" "<<p[3]<<endl; //4 4 4

指針變量p已經(jīng)指向數(shù)組中的第一個元素了,p+1表示指向同一數(shù)組中的下一個元素(并不是將p的值簡單加1)争拐,上面代碼已經(jīng)告訴我們了腋粥。

簡單分析:

1、數(shù)組元素是整型架曹,每個元素占4個字節(jié)隘冲,當執(zhí)行p+1;語句的時候,意味著使p的值(即當前地址)加4個字節(jié)绑雄,以指向下一個元素展辞。p+1的實際地址是p+1*d,d是數(shù)組元素所占的字節(jié)數(shù)。

2万牺、p+ia+i其實是一樣的罗珍,都是a[i]的地址,或者說脚粟,它們都指向數(shù)組a第i個元素覆旱。a是數(shù)組名指向數(shù)組的首元素地址,指針p也是指向數(shù)組的首元素地址珊楼,那么對地址進行相同操作結(jié)果當然相同通殃。

3、*(p+i)或者*(a+i)p+ia+i所指向的數(shù)組元素厕宗,即a[i]画舌。例如上面我們?yōu)?code>*(p+1)進行賦值,其實就是為a[1]進行賦值操作已慢。因而*(p+i)曲聂,*(a+i)a[i]這三者是等價的佑惠。

4朋腋、指向數(shù)組元素的指針變量也可以帶下標,如:p[i]與*(p+i)等價

例:有一個整型數(shù)組a膜楷,有10個元素旭咽,輸出數(shù)組的所有元素。

下標法

int main(int argc, char const *argv[])
{
  int a[10];
  cout<<"請輸入10個數(shù):"<<endl;
  for (int i = 0; i < 10; ++i)
  {
    cin>>a[i];
  }
  cout<<"輸出:"<<endl;
  for (int i = 0; i < 10; ++i)
  {
    cout<<a[i]<<" ";
  }
}

指針法:就是將a[i]改為*(a+i)

for (int i = 0; i < 10; ++i)
{
    cout<<*(a+i)<<" ";
}

用指針變量指向數(shù)組

int main(int argc, char const *argv[])
{
  int a[10];
  int *p;
  p = a;
  cout<<"請輸入10個數(shù):"<<endl;
  for (int i = 0; i < 10; ++i) // 輸入a[0]-a[9]
  {
    cin>>*(p+i);
  }
  cout<<"輸出:"<<endl;
  for (p = a; p < (a + 10); p++) // p先后指向a[0]-a[9]
  {
    cout<<*p<<" ";
  }
}

指針變量做函數(shù)形參

數(shù)組名代表數(shù)組首元素的地址赌厅,用數(shù)組名做函數(shù)的參數(shù)穷绵,傳遞的是數(shù)組首元素的地址,既然是地址特愿,那么同樣可以使用指針變量做函數(shù)形參仲墨。

函數(shù)實參與形參的結(jié)合有四種形式:

實參 形參
數(shù)組名 數(shù)組名
數(shù)組名 指針變量
指針變量 數(shù)組名
指針變量 指針變量

函數(shù)與指針

指針變量也可以指向一個函數(shù)勾缭,一個函數(shù)在編譯時被分配給一個入口地址,這個函數(shù)入口地址就稱為函數(shù)的指針目养×┯桑可以用一個指針變量指向函數(shù),然后通過該指針變量調(diào)用此函數(shù)癌蚁。

比如:求a和b中的大者,一般情況下我們會這么寫:

int main(int argc, char const *argv[])
{
  int max(int x, int y);
  int a,b,m;
  cin>>a>>b;
  m = max(a,b);
  cout<<"max= "<<m<<endl;
}
int max(int x, int y)
{
  return x > y ? x: y;
}

但是我們也可以用一個指針變量指向max函數(shù)幻梯,然后通過該指針變量調(diào)用函數(shù)。定義指向max函數(shù)的指針變量的方法是:

int (*p)(int,int); 
int:指針變量p指向的函數(shù)的類型
p:是指向函數(shù)的指針變量
(int,int):p所指向的函數(shù)中的形參的類型

指向函數(shù)的指針變量的一般形式為:函數(shù)類型(*變量名)(函數(shù)列表)

int main(int argc, char const *argv[])
{
  int max(int x, int y); // 函數(shù)聲明
  int (*p)(int, int); // 定義指向函數(shù)的指針變量p
  int a,b,m;
  p = max; // 讓p指向函數(shù)max,表示將max的入口地址賦給p
  cin>>a>>b;
  m = p(a,b);
  cout<<"max= "<<m<<endl;
}

注意:在定義指向函數(shù)的指針變量p時匈勋,(*p)兩側(cè)的括號不能省略礼旅,表示p先與*結(jié)合,它是指針變量洽洁,然后再與后面的()結(jié)合痘系,表示此指針指向函數(shù),函數(shù)的返回值是整型饿自。如果寫出了“int *p(int, int);”汰翠,由于()的優(yōu)先級高于*,它就成了聲明一個函數(shù)昭雌,這個函數(shù)的返回值是指向整型變量的指針复唤,返回指針值的函數(shù)也簡稱為指針函數(shù)。

返回指針值的函數(shù)

前面已經(jīng)提到了返回指針值的函數(shù)為指針函數(shù)烛卧。定義指針函數(shù)的形式為:類型名 *函數(shù)名(參數(shù)列表);佛纫,例如:

int *a(int x, int y);

a是函數(shù)名,調(diào)用它以后能夠得到一個指向整型數(shù)據(jù)的指針(地址)总放。x,y是函數(shù)的形參呈宇。在a的兩側(cè)分別是*和()運算符,由于()優(yōu)先級高于*局雄,因此a先與()結(jié)合表示為函數(shù)甥啄。函數(shù)前面的*表示此函數(shù)是指針型函數(shù)(函數(shù)值是指針),int為返回的指針指向的整型變量炬搭。

指針數(shù)組

如果一個數(shù)組蜈漓,其中的元素全部為指針類型數(shù)據(jù),那么該數(shù)組就是指針數(shù)組宫盔。也就是說融虽,指針數(shù)組中的每一個元素都相當于一個指針變量,它的值是地址灼芭。

一維數(shù)組的定義形式為:類型名 *數(shù)組名[數(shù)組長度];有额,例如:

int *p[4];

C中的 NULL 指針

在變量聲明的時候,如果沒有確切的地址可以賦值,為指針變量賦一個 NULL 值是一個良好的編程習(xí)慣谆吴。賦為 NULL 值的指針被稱為空指針。NULL 指針是一個定義在標準庫中的值為零的常量

#include <stdio.h>
 
int main ()
{
   int  *ptr = NULL;
   printf("ptr 的地址是 %p\n", ptr  );
   return 0;
}

當上面的代碼被編譯和執(zhí)行時苛预,它會產(chǎn)生下列結(jié)果:

ptr 的地址是 0x0

在大多數(shù)的操作系統(tǒng)上句狼,程序不允許訪問地址為 0 的內(nèi)存,因為該內(nèi)存是操作系統(tǒng)保留的热某。然而腻菇,內(nèi)存地址 0 有特別重要的意義,它表明該指針不指向一個可訪問的內(nèi)存位置昔馋。但按照慣例筹吐,如果指針包含空值(零值),則假定它不指向任何東西

如需檢查一個空指針秘遏,可以使用 if 語句丘薛,如下所示:

if(ptr)     /* 如果 p 非空,則完成 */
if(!ptr)    /* 如果 p 為空邦危,則完成 */

指向指針的指針

指向指針的指針洋侨,簡稱為指向指針的指針,也可以理解為二級指針倦蚪。

const指針

可以指定指針變量是一個常量希坚,或者指定指針變量指向的對象是一個常量。有以下幾種情況

指向常量的指針變量

定義這種指針變量的一般形式為:const 類型名 * 指針變量名陵且;

不允許通過指針變量改變它指向的對象的值裁僧,例如:

int a = 12, b = 15;
const int *p = &a; //定義p為指向整型變量a的const指針變量
*p = 15; //試圖通過p改變它指向的對象a的值,非法

上面定義了p為(const int *)型的指針變量慕购,并使其指向變量a聊疲,不能通過p來改變a的值,但是指針變量p的值(即p的指向)是可以改變的脓钾。例如:

p = &b; //p改為指向b是合法的

不要以為只要定義了(const int *)型指針變量就能保證其所指向的對象的值無法改變售睹。例如:

a = 10;

所以用指向常量的指針變量只是限制了通過指針變量改變它指向的對象的值。如果想保證a的值始終不變可训,應(yīng)當把a定義為常變量:

const int a = 16;

這樣p就成為了指向常變量的指針變量昌妹,無論用直接訪問方式還是間接訪問方式都無法改變a的值

常指針

指定指針變量的值是常量,即指針變量的指向不能改變握截。

int a = 4, b= 5;
int * const p = &a; // 指定p只能指向變量a
p = &b; // 試圖改變p的指向飞崖,不合法

定義這種指針變量的一般形式是:類型名 *const 指針變量名;

  • 這種指針變量稱為常指針變量,簡稱常指針谨胞,即指針值不能改變
  • 必須在定義時初始化固歪,指定其指向
  • 指針變量的指向p不能改變,但指針變量的指向變量的值可以改變*p = 10;
  • 注意const和位置。const在后面

指向常量的常指針

把以上兩種疊加在一起牢裳,就是指向常量的常指針變量逢防。即指針變量指向一個固定對象,該對象的值不能改變(指不能通過指針變量改變該對象的值)

int a = 4, b= 5;
const int * const p = &a; // 指定p只能指向變量a

p = &b; // 試圖改變p的指向蒲讯,不合法
*p = 10; // 試圖改變p的值忘朝,不合法
a = 10; // 直接改變a的值,合法

定義這種指針變量的一般形式為:const 基本類型名 * const 指針變量名

void指針類型

可以定義一個基類型為void的指針變量(即(void *)型變量)判帮,它不能指向任何類型的數(shù)據(jù)局嘁。注意:不要把指向void類型理解為能指向“任何類型”的數(shù)據(jù),而應(yīng)該理解為“指向空類型”或“不確定的類型”的數(shù)據(jù)

如果指針變量不指定一個確定的數(shù)據(jù)類型晦墙,它是無法訪問任何一個具體的數(shù)據(jù)的悦昵,它只通過了一個地址。在c中用malloc函數(shù)開辟動態(tài)存儲空間晌畅,函數(shù)的返回值是該空間的起始地址但指,由于該空間尚未使用,其中沒有數(shù)據(jù)抗楔,談不上指向什么類型的數(shù)據(jù)枚赡,故返回一個void *型的指針,表示它不指向確定的具有類型的數(shù)據(jù)谓谦。

顯然這種指針是過渡型的贫橙,它必須轉(zhuǎn)換為指定一個確定的數(shù)據(jù)類型的數(shù)據(jù),才能訪問實際存在的數(shù)據(jù)反粥,否則它是沒有任何用處的卢肃,在實際使用該指針變量時,要對它進行類型轉(zhuǎn)換才顿,使之適合于被賦值的變量的類型莫湘。

int a = 3; // 定義a為整型變量
int *p1 = &a; // p1指向int型變量
char *p2 = "new"; // p2指向char型變量
void *p3; // p3為無類型指針變量
p3 = (void *)p1; // 將p1的值轉(zhuǎn)換為void *類型,然后賦值給p3
//cout << *p3 << endl; //p3不能指向確定類型的變量郑气,*p3非法
cout << *(int *)p3 << endl; // 把p3的值轉(zhuǎn)換為(int *)型幅垮,可以指向指針變量a
p2 = (char *)p3; // 將p3的值轉(zhuǎn)換為char *類型,然后賦值給p2尾组,輸出3
printf("%d", *p2); //合法忙芒,輸出a的值

可以把非void型的指針付給void型指針變量,但是不能把void型指針直接付給非void型指針變量讳侨,必須先進行強轉(zhuǎn)換

引用

對于一個數(shù)據(jù)可以建立一個“引用”呵萨,它的作用是為一個變量起一個別名。這是C++對C的一個重要擴充跨跨。

假如有一個變量a潮峦,想給它起一個別名b,可以這樣寫:

int a; // 定義a為整型變量
int &b = a; // 聲明b是a的引用

以上聲明了b是a的引用,即b是a的別名忱嘹,經(jīng)過這樣的聲明后嘱腥,使用a或b的作用相同,都代表同一變量拘悦〉鳎可以這樣理解引用,通過b可以引用a窄做。聲明變量b為引用,并不需要另外開辟內(nèi)存單元來存放b的值慰技,b和a占內(nèi)存的同一個存儲單元椭盏,它們具有同一地址。即使變量b具有變量a的地址吻商,如果a的值是20,那么b的值也是20

注意:

  • 在上面的聲明中掏颊,&是引用聲明符,并不代表地址艾帐,不要理解為把a的值付給b的地址乌叶。在數(shù)據(jù)類型名后面出現(xiàn)的&聲明符是引用聲明符,在其他場合出現(xiàn)的都是地址符柒爸,如:
char c;
char &d = c; // 此處的&是引用聲明g符
int *p = &a; // 此處的&是地址符
  • 引用不是一種獨立的數(shù)據(jù)類型准浴,對引用只有聲明,沒有定義捎稚。必須先定義一個變量乐横,然后聲明對該變量建立一個引用(別名)

  • 聲明一個引用時,必須同時使之初始化今野,即聲明它代表哪一個變量葡公。

  • 在聲明一個引用后,不能再使之作為另一變量的引用条霜。比如:聲明變量b是變量a的引用后催什,在其有效的范圍內(nèi),b始終與其代表的變量a相聯(lián)系宰睡,不能再作為其他變量的引用(別名)蒲凶。下面的用法不對:

 int a1, a2;
 int &b = a1; // 聲明b是a1的引用
 int &b = a2; // 試圖使b又變成a2的別名,不合法
  • 不能建立引用數(shù)組拆内。如:
int a[5];
int &b[5] = a; //錯誤豹爹,不能建立引用數(shù)組
int &b = a[0]; //錯誤,不能作為數(shù)組元素的別名
  • 不能建立引用的引用矛纹。如:
int a = 3;
int &b = a; // 聲明b是a的別名臂聋,正確
int &c = b; //試圖建立引用的引用,錯誤
  • 可以取引用的地址。如已聲明b是a的引用孩等,則&b就是變量a的地址&a
int *p;
*p = &b;
引用作為函數(shù)參數(shù)

C++之所以增加引用機制艾君,主要是把它作為函數(shù)參數(shù),以擴充函數(shù)傳遞數(shù)據(jù)的功能肄方。

函數(shù)參數(shù)傳遞有兩種情況

1冰垄、將變量名作為實參和形參。這時傳給形參的是變量的值权她,傳遞是單向的虹茶。如果在執(zhí)行函數(shù)形參的值發(fā)生變化,并不傳回給實參隅要。因此在調(diào)用函數(shù)時蝴罪,形參和實參不是同一個存儲單元。

要求將變量i和j的值互換步清。下面的程序無法實現(xiàn)

int main(int argc, const char * argv[]) {
    void swap(int , int); // 函數(shù)聲明
    int i = 3, j = 5;
    swap(i, j); // 調(diào)用函數(shù)swap
    cout << i << "" << j << endl; // i和j的值并未互換

    return 0;
}

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

為了解決這個問題要门,采用傳遞變量地址的方法

2、傳遞變量的地址廓啊。形參是指針變量欢搜,實參是一個變量的地址,調(diào)用函數(shù)時谴轮,形參(指針變量)得到實參變量的地址炒瘟,因此指向?qū)崊⒆兞繂卧?/p>

int main(int argc, const char * argv[]) {

    void swap(int *, int *); // 函數(shù)聲明
    int i = 3, j = 5;
    swap(&i, &j); // 調(diào)用函數(shù)swap
    cout << i << "" << j << endl; // 5 3

    return 0;
}

void swap(int *p1, int *p2)
{
    int temp;
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

其實上面這種虛實結(jié)合的方法仍然是“值傳遞”方式,只是實參的值是變量的地址而已第步。通過形參指針變量訪問主函數(shù)中的變量(i和j)唧领,并改變它們的值

3、以引用作為形參雌续,在虛實結(jié)合時建立變量的引用斩个,使形參名作為實參的“引用”。即形參成為實參的引用

int main(int argc, const char * argv[]) {
    void swap(int &, int &); // 函數(shù)聲明
    int i = 3, j = 5;
    swap(i, j); // 實參為整型變量
    cout << i << " " << j << endl; // 5 3
    return 0;
}

void swap(int &a, int &b) // 行參是引用
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}

在定義swap函數(shù)聲明行參時驯杜,指定a和b是整型變量的引用受啥。注意:此處&a不是a的地址,而是指a是一個整型變量的引用(別名),&是引用聲明符鸽心。由于是形參滚局,不必對它初始化,即未指定它們是哪個變量的別名顽频。

當main函數(shù)調(diào)用swap函數(shù)時藤肢,進行虛實結(jié)合,把實參變量i和j的地址傳給形參a和b糯景。這樣i和a的地址相同嘁圈,二者是同一變量省骂,即a成為i的別名,同理b成為j的別名最住。那么在swap函數(shù)中使a和b的值對換钞澳,顯然i和j的值同時也改變了。這就是地址傳遞方式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涨缚,一起剝皮案震驚了整個濱河市轧粟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脓魏,老刑警劉巖兰吟,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異茂翔,居然都是意外死亡混蔼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門檩电,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人府树,你說我怎么就攤上這事俐末。” “怎么了奄侠?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵卓箫,是天一觀的道長。 經(jīng)常有香客問我垄潮,道長烹卒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任凑队,我火速辦了婚禮消约,結(jié)果婚禮上胜嗓,老公的妹妹穿的比我還像新娘。我一直安慰自己藐吮,他們只是感情好,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布逃贝。 她就那樣靜靜地躺著谣辞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沐扳。 梳的紋絲不亂的頭發(fā)上泥从,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機與錄音沪摄,去河邊找鬼躯嫉。 笑死纱烘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的和敬。 我是一名探鬼主播凹炸,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昼弟!你這毒婦竟也來了啤它?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤舱痘,失蹤者是張志新(化名)和其女友劉穎变骡,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芭逝,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡塌碌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了旬盯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片台妆。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖胖翰,靈堂內(nèi)的尸體忽然破棺而出接剩,到底是詐尸還是另有隱情,我是刑警寧澤萨咳,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布懊缺,位于F島的核電站,受9級特大地震影響培他,放射性物質(zhì)發(fā)生泄漏鹃两。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一舀凛、第九天 我趴在偏房一處隱蔽的房頂上張望俊扳。 院中可真熱鬧,春花似錦猛遍、人聲如沸拣度。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抗果。三九已至,卻和暖如春奸晴,著一層夾襖步出監(jiān)牢的瞬間冤馏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工寄啼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逮光,地道東北人代箭。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像涕刚,于是被迫代替她去往敵國和親嗡综。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容