精簡版:
指針:變量,獨立,可變,可空,替身,無類型檢查;
引用:別名,依賴,不變,非空,本體,有類型檢查;
完整版:
1. 概念
指針從本質上講是一個變量,變量的值是另一個變量的地址,指針在邏輯上是獨立的,它可以被改變的,包括指針變量的值(所指向的地址)和指針變量的值對應的內存中的數據(所指向地址中所存放的數據)。
引用從本質上講是一個別名,是另一個變量的同義詞,它在邏輯上不是獨立的,它的存在具有依附性,所以引用必須在一開始就被初始化(先有這個變量,這個實物,這個實物纔能有別名),而且其引用的對象在其整個生命週期中不能被改變,即自始至終只能依附於同一個變量(初始化的時候代表的是誰的別名,就一直是誰的別名,不能變)。
2. C++中的指針參數傳遞和引用參數傳遞
指針參數傳遞本質上是值傳遞,它所傳遞的是一個地址值。值傳遞過程中,被調函數的形式參數作爲被調函數的局部變量處理,會在棧中開闢內存空間以存放由主調函數傳遞進來的實參值,從而形成了實參的一個副本(替身)。值傳遞的特點是,被調函數對形式參數的任何操作都是作爲局部變量進行的,不會影響主調函數的實參變量的值(形參指針變了,實參指針不會變)。
引用參數傳遞過程中,被調函數的形式參數也作爲局部變量在棧中開闢了內存空間,但是這時存放的是由主調函數放進來的實參變量的地址。被調函數對形參(本體)的任何操作都被處理成間接尋址,即通過棧中存放的地址訪問主調函數中的實參變量(根據別名找到主調函數中的本體)。因此,被調函數對形參的任何操作都會影響主調函數中的實參變量。
引用傳遞和指針傳遞是不同的,雖然他們都是在被調函數棧空間上的一個局部變量,但是任何對於引用參數的處理都會通過一個間接尋址的方式操作到主調函數中的相關變量。而對於指針傳遞的參數,如果改變被調函數中的指針地址,它將應用不到主調函數的相關變量。如果想通過指針參數傳遞來改變主調函數中的相關變量(地址),那就得使用指向指針的指針或者指針引用。
從編譯的角度來講,程序在編譯時分別將指針和引用添加到符號表上,符號表中記錄的是變量名及變量所對應地址。指針變量在符號表上對應的地址值爲指針變量的地址值,而引用在符號表上對應的地址值爲引用對象的地址值(與實參名字不同,地址相同)。符號表生成之後就不會再改,因此指針可以改變其指向的對象(指針變量中的值可以改),而引用對象則不能修改。
3. 總結
相同點:
都是地址的概念
不同點:
指針是一個實體(替身);引用只是一個別名(本體的另一個名字)
引用只能在定義時被初始化一次,之後不可改變,即“從一而終”;指針可以修改,即“見異思遷”;
引用不能爲空(有本體,纔有別名);指針可以爲空;
sizeof 引用,得到的是所指向變量的大小;sizeof 指針,得到的是指針的大小;
指針 ++,是指指針的地址自增;引用++是指所指變量自增;
引用是類型安全的,引用過程會進行類型檢查;指針不會進行安全檢查;
1. 值傳遞
1 void f( int p){ 2 printf("\n%x",&p); 3 printf("\n%x",p); 4 p=0xff; 5 } 6 void main() 7 { 8 int a=0x10; 9 printf("\n%x",&a); 10 printf("\n%x\n",a); 11 f(a); 12 printf("\n%x\n",a); 13 }
通過上例我們可以看到,int a=0x10,存放的地址爲0x12ff44,值爲10,當調用f(a)時,傳遞給p的值爲10,但是p的地址爲0x12fef4,當改變p=0xff,時是改變地址爲0x12fef4中的內容,並沒有改變0x12ff44中的內容,所以調用f(a),後a的值仍然爲0x10,所以值傳遞無法改變變量的值。示意圖如下:
2. 引用傳遞
1 void f( int & p){ 2 printf("\n%x",&p); 3 printf("\n%x",p); 4 p=0xff; 5 } 6 void main() 7 { 8 int a=0x10; 9 printf("\n%x",&a); 10 printf("\n%x\n",a); 11 f(a); 12 printf("\n%x\n",a); 13 }
通過上面引用傳遞傳遞案例我們可以看到,調用f(a)時,傳遞給p的是a的地址,所以p和a的地址都是0X12ff44,所以p就是a,改變p當然能改變a。示意圖如下:
3. 指針傳遞
1 void f( int*p){ 2 printf("\n%x",&p); 3 printf("\n%x",p); 4 printf("\n%x\n",*p); 5 *p=0xff; 6 } 7 void main() 8 { 9 int a=0x10; 10 printf("\n%x",&a); 11 printf("\n%x\n",a); 12 f(&a); 13 printf("\n%x\n",a); 14 }
通過指針傳遞的案例我們可以看到,調用f(&a)是將a的地址0x12ff44傳遞給p,則*p就指向了a的內容,改變*p後,a的內容自然就改變了,示意圖如下:
4. 指針的引用傳遞
1 void f( int*&p){ 2 printf("\n%x",&p); 3 printf("\n%x",p); 4 printf("\n%x\n",*p); 5 *p=0xff; 6 } 7 void main() 8 { 9 int a=0x10; 10 printf("\n%x",&a); 11 printf("\n%x\n",a); 12 int *b=&a; 13 printf("\n%x",&b); 14 printf("\n%x",b); 15 printf("\n%x\n",*b); 16 f(b); 17 printf("\n%x\n",a); 18 }
爲了使用指針的引用傳遞我們要新建一個指針b,然後將b的引用傳遞給p,其實p就是b的一個拷貝,*p=*b都指向a,所以改變*p的內容也就改變a的內容。示意圖如下:
我們再來看一下如果不用指針的引用傳遞會出現什麼結果
1 void f( int*p){ 2 printf("\n%x",&p); 3 printf("\n%x",p); 4 printf("\n%x\n",*p); 5 *p=0xff; 6 } 7 void main() 8 { 9 int a=0x10; 10 printf("\n%x",&a); 11 printf("\n%x\n",a); 12 int *b=&a; 13 printf("\n%x",&b); 14 printf("\n%x",b); 15 printf("\n%x\n",*b); 16 f(b); 17 printf("\n%x\n",a); 18 printf("\n%x\n",b); 19 }
從結果中我們可以看到調用f(b)時,傳遞給p的是b的內容,但是&b,和&p是不一樣的,雖然*p和*b都指向a。示意圖如下:
作者: ZH奶酪——張賀
Q Q: 1203456195
郵箱: [email protected]
出處: http://www.cnblogs.com/CheeseZH/
* 本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。