1. 程式人生 > >VC 學習之三,引用與指標

VC 學習之三,引用與指標

從概念上講。指標從本質上講就是存放變數地址的一個變數,在邏輯上是獨立的,它可以被改變,包括其所指向的地址的改變和其指向的地址中所存放的資料的改變。

而引用是一個別名,它在邏輯上不是獨立的,它的存在具有依附性,所以引用必須在一開始就被初始化,而且其引用的物件在其整個生命週期中是不能被改變的(自始至終只能依附於同一個變數)。

C++中,指標和引用經常用於函式的引數傳遞,然而,指標傳遞引數和引用傳遞引數是有本質上的不同的:

指標傳遞引數本質上是值傳遞的方式,它所傳遞的是一個地址值。值傳遞過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在棧中開闢了記憶體空間以存放由主調函式放進來的實參的值,從而成為了實參的一個副本。值傳遞的特點是被調函式對形式引數的任何操作都是作為區域性變數進行,不會影響主調函式的實參變數的值。

而在引用傳遞過程中,被調函式的形式引數雖然也作為區域性變數在棧中開闢了記憶體空間,但是這時存放的是由主調函式放進來的實參變數的地址。被調函式對形參的任何操作都被處理成間接定址,即通過棧中存放的地址訪問主調函式中的實參變數。正因為如此,被調函式對形參做的任何操作都影響了主調函式中的實參變數。

引用傳遞和指標傳遞是不同的,雖然它們都是在被調函式棧空間上的一個區域性變數,但是任何對於引用引數的處理都會通過一個間接定址的方式操作到主調函式中的相關變數。而對於指標傳遞的引數,如果改變被調函式中的指標地址,它將影響不到主調函式的相關變數。如果想通過指標引數傳遞來改變主調函式中的相關變數,那就得使用指向指標的指標,或者指標引用。

為了進一步加深大家對指標和引用的區別,下面我從編譯的角度來闡述它們之間的區別:

程式在編譯時分別將指標和引用新增到符號表上,符號表上記錄的是變數名及變數所對應地址。指標變數在符號表上對應的地址值為指標變數的地址值,而引用在符號表上對應的地址值為引用物件的地址值。符號表生成後就不會再改,因此指標可以改變其指向的物件(指標變數中的值可以改),而引用物件則不能修改。

最後,總結一下指標和引用的相同點和不同點:

相同點:

●都是地址的概念;

指標指向一塊記憶體,它的內容是所指記憶體的地址;而引用則是某塊記憶體的別名。

不同點:

●指標是一個實體,而引用僅是個別名;

●引用只能在定義時被初始化一次,之後不可變;指標可變;引用“從一而終”,指標可以“見異思遷”;

●引用沒有const,指標有constconst的指標不可變;

●引用不能為空,指標可以為空;

●“sizeof 引用”得到的是所指向的變數(物件)的大小,而“sizeof 指標”得到的是指標本身的大小;

●指標和引用的自增(++)運算意義不一樣;

●引用是型別安全的,而指標不是 (引用比指標多了型別檢查

例1 :直接string ,則是傳值方式
#include "stdafx.h"
#include <iostream>
#include <string>
 
using namespace std;
 
void swap (string ,string ); //使用string 類的物件作為函式引數
 
void main()
{
string str1("現在") ,str2("過去");
swap(str1,str2);
cout<<"返回後,str1="<<str1<<" str2 = "<<str2<<endl;
//返回後,str1=現在 str2 = 過去
} 
 
void swap(string str1,string str2)
{
string tmp =str1;
str1 = str2;
str2 = tmp;
cout<<"交換為: str1 = "<<str1<<" str2 = "<<str2<<endl;
//交換為: str1 = 過去 str2 = 現在
//直接使用基本資料型別的物件,或使用類和結構的物件作為引數,均是傳值方式
}


例2:傳指標,則通過指標的指標訪問資料值,改變此值會改變主調函式中的值
#include "stdafx.h"
#include <iostream>
#include <string>
 
using namespace std;
 
void swap (string * ,string *); //使用string 類的指標作為函式引數
 
void main()
{
string str1("現在") ,str2("過去");
swap(&str1,&str2); //傳地址值
cout<<"返回後,str1="<<str1<<" str2 = "<<str2<<endl;
//返回後,str1=過去 str2 = 現在
} 
 
void swap(string * str1,string * str2) //指標作為引數,此處可以新增const,則實參的值不可修改了
{
string tmp =* str1;
*str1 = * str2; //指標的指標,會影響到主調函式中的相關變數
*str2 = tmp;
cout<<"交換為: str1 = "<<*str1<<" str2 = "<<*str2<<endl; //輸出指標的指標,即主調函式中的值
//交換為: str1 = 過去 str2 = 現在
//指標的指標,會影響到主調函式中的相關變數
}


例3:傳引用,引用是實參的別名,修改引用的值,直接修改了主調函式的值
#include "stdafx.h"
#include <iostream>
#include <string>
 
using namespace std;
 
void swap (string & ,string &); //使用string 類的引用作為引數
 
void main()
{
string str1("現在") ,str2("過去");
swap(str1,str2); //傳的是物件的名字
cout<<"返回後,str1="<<str1<<" str2 = "<<str2<<endl;
//返回後,str1=過去 str2 = 現在
} 
 
void swap(string & str1,string & str2) //指標作為引數
{
string tmp = str1;
str1 =  str2; //引用的形參是主調函式的別名,修改值,其實是修改了主調函式的值
str2 = tmp;
cout<<"交換為: str1 = "<<str1<<" str2 = "<<str2<<endl;
//交換為: str1 = 過去 str2 = 現在
//傳引用,修改後,直接會改掉了主調函式的值
}