C/C++按值傳遞和按地址傳遞
C/C++的按值傳遞和按地址傳遞有明顯不同,下面對他們作個區別:
按值傳遞:在呼叫函式中將原函式的值拷貝一份過去被呼叫的函式,在被呼叫函式中對該值的修改不會影響原函式的值。
按地址傳遞:在呼叫函式的時候將原函式的值所在的地址拷貝一份過去,被呼叫函式對這個地址所作的修改會影響原來的值。
鑑於本人表達能力有限,這樣說可能有點迷惑,下面直接上圖:
一、按值傳遞
#include<iostream> using namespace std; void changeNumber(int x); int main(void) { int a = 10; cout << "a = " << a << endl; changeNumber(a); cout << "Now a = " << a << endl; return 0; } void changeNumber(int x) { x = x + 5; }
這裡是一個十分簡單的程式,其中包含了一個changeNumber()函式,意圖是改變在main()函式中變數 a 的值,顯而易見,這是一種按值傳遞,changeNumber()函式不可能完成任務:
可以看到,a並沒有被改變。原因很簡單,按值傳遞,當呼叫changeNumber()函式的時候,以 a 作為實際引數,在程式跳到changeNumber()函式的時候,會拷貝一份a的資料,也就是說,在記憶體空間中重新開闢了一塊空間,它的作用就是用來儲存a的值,並且這塊空間的名稱為 x,也就是changeNumber()中的這個x,注意,這個x所在的空間和a所在的空間是完全不同的兩塊記憶體(通過對他們分別輸出地址可以得出),既然他們根本不屬於同個地方,那麼對x所作的任何修改都無法影響a。
二、按地址傳遞
如果這麼寫程式碼:
#include<iostream>
using namespace std;
void changeNumber(int* x);
int main(void)
{
int a = 10;
cout << "a = " << a << endl;
changeNumber(&a);
cout << "Now a = " << a << endl;
return 0;
}
void changeNumber(int* x)
{
*x = *x + 5;
}
這裡的程式碼就是按地址傳遞,首先在changeNumber()的宣告中,使用了int*型別而不是int型別,其次在main()函式呼叫changeNumber()函式的時候使用的實參是&a而不是a,這就傳遞了一個地址給changeNumber()函式,這個changeNumber()就可以完成修改a的任務:
按照我的理解,按地址傳遞實際上是一種特殊的按值傳遞,原因如下:
1.main()函式呼叫changeNumber()的時候,將a的地址,也就是&a傳遞給changeNumber()函式,這實際上就是將a的地址拷貝一份過去給changeNumber()函式,在前面的例子中,main()拷貝並傳遞的是a,這裡main()拷貝並傳遞的是&a,兩者都可以理解為按值傳遞,只不過第二個例子中的“值”是a的地址而已
2.changeNumber()函式被呼叫之後,它根據傳過來的地址值(請注意,這裡說的是地址值,因為地址本身也是一個可見的數值),在記憶體中開闢一塊新的空間,這塊空間是用來儲存這個地址值的,換句話說,這塊空間上的內容就是a的地址,這似乎有點難以理解,但事實就是這樣的,然後使用 * 運算子對x進行操作,*x操作的就是a的具體的值,而x作為一個指標,它存有a的地址(或者說它指向a的地址),那麼對*x所做的任何操作都會影響a的值。
拓展:
對於第二個例子,如果使用cout輸出x,結果得到的將會是一個地址,並且這個地址與a的相同,這符合我前面所敘述的內容。
#include<iostream>
using namespace std;
void changeNumber(int* x);
int main(void)
{
int a = 10;
cout << "a = " << a << endl;
changeNumber(&a);
cout << "Now a = " << a << endl;
cout << "&a = " << &a << endl;
return 0;
}
void changeNumber(int* x)
{
*x = *x + 5;
cout << "x = " << x << endl;
}
好,現在把注意點集中到這行程式碼上:
cout << "&x = " << &x << endl;
對這個&x進行輸出,結果得到的又是另一個地址,事實上,這個地址就是呼叫changeNumber()函式時分配的記憶體空間,這塊記憶體空間儲存的便是x也是a的地址,當函式結束後,這塊空間會被收回,上面的x的內容也會消失。
前面說了x存放的是a的地址,也就是說,x指向a的地址,如果有操作:
x = x + 5
把這行程式碼新增到changeNumber()函式的最前面,即:
void changeNumber(int* x) { x = x + 5; *x = *x + 5; cout << "x = " << x << endl; }
這樣會發生的事情是:這個函式又無法完成修改main中a的值了,原因就是,x存放的不再是a的地址,x的值已經發生了移動,換句話說,x指向了別的地址。
由於C和C++語法的相似性,經過C環境下寫出的程式碼,同樣符合這個邏輯
之所以寫這個東西,是因為看到有博主寫了關於Java按值傳遞和按引用傳遞的文章,連結:
https://blog.csdn.net/javazejian/article/details/51192130
剛好最近在學Java,文章所述Java的按值傳遞和按引用傳遞使我對C++按值傳遞和按地址傳遞的理解產生了疑問,一番實驗之後終於弄清楚了。原文章寫的非常不錯,建議同樣正在學習Java的同學可以看一看。