最近寫了幾篇深層次討論陣列和指標的文章,其中提到了「c語言中,所有非陣列的形式引數傳遞均以值傳遞形式」
而關於值傳遞,指標傳遞,引用傳遞這幾個方面還會存在誤區, 所有我覺的有必要在這裡也說明一下~
下文會通過例子詳細說明哦
值傳遞:
形參是實參的拷貝,改變形參的值並不會影響外部實參的值。從被呼叫函式的角度來說,值傳遞是單向的(實參->形參),引數的值只能傳入,
不能傳出。當函式內部需要修改引數,並且不希望這個改變影響呼叫者時,採用值傳遞。
指標傳遞:
形參為指向實參位址的指標,當對形參的指向操作時,就相當於對實參本身進行的操作
引用傳遞:
形參相當於是實參的「別名」,對形參的操作其實就是對實參的操作,在引用傳遞過程中,被調函式的形式引數雖然也作為區域性變數在棧
中開闢了記憶體空間,但是這時存放的是由主調函式放進來的實參變數的位址。被調函式對形參的任何操作都被處理成間接定址,即通過
棧中存放的位址訪問主調函式中的實參變數。正因為如此,被調函式對形參做的任何操作都影響了主調函式中的實參變數。
理論性的就不多說,
下面的**對此作出了細緻解釋(從實參,形參在記憶體中存放位址的角度 說明了問題的本質,容易理解 )
1 #include執行結果如下,(不同的機器可能會有所差別)2using
namespace std;3//
值傳遞4
void change1(int n)89
//引用傳遞
10void change2(int & n)
14//
指標傳遞
15void change3(int *n)
19int main()
可以看出,實參的位址為0x22ff44
採用值傳遞的時候,函式操作的位址是0x22ff20並不是實參本身,所以對它進行操作並不能改變實參的值
再看引用傳遞,操作位址就是實參位址 ,只是相當於實參的乙個別名,對它的操作就是對實參的操作
接下來是指標傳遞,也可發現操作位址是實參位址
那麼,引用傳遞和指標傳遞有什麼區別嗎?
引用的規則:
(1)引用被建立的同時必須被初始化(指標則可以在任何時候被初始化)。
(2)不能有null引用,引用必須與合法的儲存單元關聯(指標則可以是null)。
(3)一旦引用被初始化,就不能改變引用的關係(指標則可以隨時改變所指的物件)。
指標傳遞的實質:
指標傳遞引數本質上是值傳遞的方式,它所傳遞的是乙個位址值。值傳遞過程中,被調函式的形式引數作為被調函式的區域性變數處理,
即在棧中開闢了記憶體空間以存放由主調函式放進來的實參的值,從而成為了實參的乙個副本。值傳遞的特點是被調函式對形式引數的
任何操作都是作為區域性變數進行,不會影響主調函式的實參變數的值。(這裡是在說實參指標本身的位址值不會變)如果理解不了大可跳過這段
指標傳遞和引用傳遞一般適用於:
函式內部修改引數並且希望改動影響呼叫者。對比指標/引用傳遞可以將改變由形參「傳給」實參(實際上就是直接在實參的記憶體上修改,
不像值傳遞將實參的值拷貝到另外的記憶體位址中才修改)。
另外一種用法是:當乙個函式實際需要返回多個值,而只能顯式返回乙個值時,可以將另外需要返回的變數以指標/引用傳遞
給函式,這樣在函式內部修改並且返回後,呼叫者可以拿到被修改過後的變數,也相當於乙個隱式的返回值傳遞吧。
以下是我覺得關於指標和引用寫得很不錯的文章,大家可參照看一下,原文出處位址:
從概念上講。指標從本質上講就是存放變數位址的乙個變數,在邏輯上是獨立的,它可以被改變,包括其所指向的位址的改變和其指向的位址中所存放的資料的改變。
而引用是乙個別名,它在邏輯上不是獨立的,它的存在具有依附性,所以引用必須在一開始就被初始化,而且其引用的物件在其整個生命週期中是不能被改變的(自始至終只能依附於同乙個變數)。
在c++中,指標和引用經常用於函式的引數傳遞,然而,指標傳遞引數和引用傳遞引數是有本質上的不同的:
指標傳遞引數本質上是值傳遞的方式,它所傳遞的是乙個位址值。值傳遞過程中,被調函式的形式引數作為被調函式的區域性變數處理,即在棧中開闢了記憶體空間以存放由主調函式放進來的實參的值,從而成為了實參的乙個副本。值傳遞的特點是被調函式對形式引數的任何操作都是作為區域性變數進行,不會影響主調函式的實參變數的值。(這裡是在說實參指標本身的位址值不會變)
而在引用傳遞過程中,被調函式的形式引數雖然也作為區域性變數在棧中開闢了記憶體空間,但是這時存放的是由主調函式放進來的實參變數的位址。被調函式對形參的任何操作都被處理成間接定址,即通過棧中存放的位址訪問主調函式中的實參變數。正因為如此,被調函式對形參做的任何操作都影響了主調函式中的實參變數。
引用傳遞和指標傳遞是不同的,雖然它們都是在被調函式棧空間上的乙個區域性變數,但是任何對於引用引數的處理都會通過乙個間接定址的方式操作到主調函式中的相關變數。而對於指標傳遞的引數,如果改變被調函式中的指標位址,它將影響不到主調函式的相關變數。如果想通過指標引數傳遞來改變主調函式中的相關變數,那就得使用指向指標的指標,或者指標引用。
程式在編譯時分別將指標和引用新增到符號表上,符號表上記錄的是變數名及變數所對應位址。指標變數在符號表上對應的位址值為指標變數的位址值,而引用在符號表上對應的位址值為引用物件的位址值。符號表生成後就不會再改,因此指標可以改變其指向的物件(指標變數中的值可以改),而引用物件則不能修改。
最後,總結一下指標和引用的相同點和不同點:
★相同點:
●都是位址的概念;
指標指向一塊記憶體,它的內容是所指記憶體的位址;而引用則是某塊記憶體的別名。
★不同點:
●指標是乙個實體,而引用僅是個別名;
●引用只能在定義時被初始化一次,之後不可變;指標可變;引用「從一而終」,指標可以「見異思遷」;
●引用沒有const,指標有const,const的指標不可變;(具體指沒有int& const a這種形式,而const int& a是有 的, 前者指引用本身即別名不可以改變,這是當然的,所以不需要這種形式,後者指引用所指的值不可以改變)
●引用不能為空,指標可以為空;
●「sizeof 引用」得到的是所指向的變數(物件)的大小,而「sizeof 指標」得到的是指標本身的大小;
●指標和引用的自增(++)運算意義不一樣;
●引用是型別安全的,而指標不是(引用比指標多了型別檢查)
一、引用的概念一條魚@引用引入了物件的乙個同義詞。定義引用的表示方法與定義指標相似,只是用&代替了*。
例如: point pt1(10,10);
point &pt2=pt1; 定義了pt2為pt1的引用。通過這樣的定義,pt1和pt2表示同一物件。
需要特別強調的是引用並不產生物件的副本,僅僅是物件的同義詞。因此,當下面的語句執行後:
pt1.offset(2,2);
pt1和pt2都具有(12,12)的值。
引用必須在定義時馬上被初始化,因為它必須是某個東西的同義詞。你不能先定義乙個引用後才
初始化它。例如下面語句是非法的:
point &pt3;
pt3=pt1;
那麼既然引用只是某個東西的同義詞,它有什麼用途呢?
下面討論引用的兩個主要用途:作為函式引數以及從函式中返回左值。
二、引用引數
1、傳遞可變引數
傳統的c中,函式在呼叫時引數是通過值來傳遞的,這就是說函式的引數不具備返回值的能力。
所以在傳統的c中,如果需要函式的引數具有返回值的能力,往往是通過指標來實現的。比如,實現
兩整數變數值交換的c程式如下:
void swapint(int *a,int *b)
使用引用機制後,以上程式的c++版本為:
void swapint(int &a,int &b)
呼叫該函式的c++方法為:swapint(x,y); c++自動把x,y的位址作為引數傳遞給swapint函式。
2、給函式傳遞大型物件
當大型物件被傳遞給函式時,使用引用引數可使引數傳遞效率得到提高,因為引用並不產生物件的
副本,也就是引數傳遞時,物件無須複製。下面的例子定義了乙個有限整數集合的類:
const maxcard=100;
class set
//建構函式
friend set operator * (set ,set ) ; //
過載運算符號*,用於計算集合的交集 用物件作為傳值引數
//friend set operator * (set & ,set & ) 過載運算符號*,用於計算集合的交集 用物件的引用作為傳值引數
...}
先考慮集合交集的實現
set operator *( set set1,set set2)
return res;
}由於過載運算子不能對指標單獨操作,我們必須把運算數宣告為 set 型別而不是 set * 。
每次使用*做交集運算時,整個集合都被複製,這樣效率很低。我們可以用引用來避免這種情況。
set operator *( set &set1,set &set2)
return res;
}三、引用返回值
如果乙個函式返回了引用,那麼該函式的呼叫也可以被賦值。這裡有一函式,它擁有兩個引用引數並返回乙個雙精度數的引用:
double &max(double &d1,double &d2)
由於max()函式返回乙個對雙精度數的引用,那麼我們就可以用max() 來對其中較大的雙精度數加1:
max(x,y)+=1.0;
C 值傳遞 指標傳遞 引用傳遞詳解
值傳遞 形參是實參的拷貝,改變形參的值並不會影響外部實參的值。從被呼叫函式的角度來說,值傳遞是單向的 實參 形參 引數的值只能傳入,不能傳出。當函式內部需要修改引數,並且不希望這個改變影響呼叫者時,採用值傳遞。指標傳遞 形參為指向實參位址的指標,當對形參的指向操作時,就相當於對實參本身進行的操作.引...
C 值傳遞 指標傳遞 引用傳遞詳解
最近寫了幾篇深層次討論陣列和指標的文章,其中提到了 c語言中,所有非陣列的形式引數傳遞均以值傳遞形式 而關於值傳遞,指標傳遞,引用傳遞這幾個方面還會存在誤區,所有我覺的有必要在這裡也說明一下 下文會通過例子詳細說明哦 值傳遞 形參是實參的拷貝,改變形參的值並不會影響外部實參的值。從被呼叫函式的角度來...
C 值傳遞 指標傳遞 引用傳遞詳解
而關於值傳遞,指標傳遞,引用傳遞這幾個方面還會存在誤區,所有我覺的有必要在這裡也說明一下 下文會通過例子詳細說明哦 值傳遞 形參是實參的拷貝,改變形參的值並不會影響外部實參的值。從被呼叫函式的角度來說,值傳遞是單向的 實參 形參 引數的值只能傳入,不能傳出。當函式內部需要修改引數,並且不希望這個改變...