傳值,傳指針和傳引用區別和聯繫
其實,不用分爲三類,只有兩類即可。傳值和傳引用。爲什麼會出現傳地址(即傳指針)呢?本質就是大家一致對傳值和傳地址概念的理解錯誤導致,也是對指針的概念的理解錯誤導致。
指針:指針就是一個變量,如果非要說是一個特殊的變量也不爲過,因爲指針的初始化和解引用等不同的操作方式而已。就內存的分佈來說,指針和一個變量在內存中存放是沒有任何區別的,無非指針存放的是變量的地址。
傳值:傳值無非就是實參拷貝傳遞給形參,單向傳遞(實參->形參),賦值完畢後實參就和形參沒有任何聯繫,對形參的修改就不會影響到實參。
傳地址:爲什麼說傳地址也是一種傳值呢?因爲傳地址是把實參地址的拷貝傳遞給形參。還是一句話,傳地址就是把實參的地址複製給形參。複製完畢後實參的地址和形參的地址沒有任何聯繫,對實參形參地址的修改不會影響到實參, 但是對形參地址所指向對象的修改卻直接反應在實參中,因爲形參指向的對象就是形參的對象。
傳引用:傳引用本質沒有任何實參的拷貝,一句話,就是讓另外一個變量也執行該實參。就是兩個變量指向同一個對象。這是對形參的修改,必然反映到實參上。
#include<iostream>
using namespace std;
void Value(int n)
{
cout << "Value(int n)"<< endl;
cout << "{" << endl;
cout << " &n=" << &n << endl;
cout << "}" << endl;
n++;
}
void Reference(int &n)
{
cout << "Reference(int &n)" << endl;
cout << "{" << endl;
cout << " n=" << n << " &n=" << &n << endl;
cout << "}" << endl;
n++;
}
void Pointer(int *n)
{
cout << "Pointer(int *n)" << endl;
cout << "{" << endl;
cout << " n=" << n << " &n=" << &n << endl;
(*n)++;
int b = 20;
cout << " b=" << b << " n = &b" << endl;
n = &b;
cout << " n=" << n << " &n=" << &n << endl;
(*n)++;
cout << "}" << endl;
}
int main()
{
int n = 10;
cout << "n = " << 10 << " &n=" << &n << endl<< endl;
Value(n);
cout << "after Value() n=" << n << endl << endl;
Reference(n);
cout << "after Reference() n=" << n << endl << endl;
Pointer(&n);
cout << "after Pointer() n=" << n << endl << endl ;
system("pause");
return true;
}
值傳遞時函數操作的並不是實參本身,形參和實參是相互獨立的,所以對形參進行操作並不會改變實參的值。
引用傳遞操作地址是實參地址 ,形參相當於實參的一個別名,對它的操作就是對實參的操作。
指針傳遞時,可以通過指針操作實參,同樣可以改變實參的值。
指針傳遞參數本質上是值傳遞的方式,它所傳遞的是一個地址值。值傳遞的特點是被調函數對形式參數的任何操作都是作爲局部變量進行,不會影響主調函數的實參變量的值。
在值傳遞過程中,被調函數的形式參數作爲被調函數的局部變量,即在棧中開闢了內存空間以存放由主調函數放進來的實參的值,前面說過,值傳遞是單向傳遞(實參->形參),賦值完畢後實參就和形參沒有任何聯繫。那指針傳遞是怎麼通過這個局部變量訪問實參的呢,當然是通過局部變量中存儲的地址。
一、值傳遞
值傳遞,這與C函數的性質有關。C函數的所有參數均以“傳值調用”方式進行傳遞,這意味着函數值將獲得參數值的一份拷貝,函數可以放心修改這個拷貝值,而不必擔心會修改調用程序實際傳給他的參數。
我們先來看實現函數swap1:
執行結果如下:
實參a的地址爲:0018FF44,實參b的地址爲0018FF40
棧區(stack)— 程序運行時由編譯器自動分配,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。程序結束時由編譯器自動釋放。因此,參數a,b是存放在棧區的。在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。因此,我們會看到a,b的地址是呈減少的趨勢。
因此,按照“值傳遞”的思想,形參是實參的拷貝,程序會開闢一塊新的棧區爲形參。它們進行交換操作是在這塊新的棧區裏面,並不影響實參的那一塊內存。
執行完swap1函數,形參的內存中a,b的值發生了變化,但並不影響實參的的值。
在函數調用時,參數是從右到左讀的,所以b的地址比a的地址高
二、指針傳遞
我們來看實現函數swap2:
運行結果:
因此我們可以看到,形參的值實際是實參的地址,因爲c語言是值傳遞,main函數中傳入的是&a,&b即a,b的地址,所以形參中存儲的也是a和b的地址。
然後執行:
*a是什麼意思?*a是地址爲a的內存中所存儲的函數值。所以上面三條語句的意思就是地址爲a的內存中所存儲的函數值與地址爲b的內存中所存儲的函數值進行交換。如下圖:
因此,他修改的是實參的內容。執行完後實參的內容應該是這樣的:
所以,這個時候a的值爲6,b的值爲5。
三、引用傳遞
我們來看實現函數swap3:
執行結果截圖: