1. 程式人生 > >C/C++按值傳遞和按地址傳遞

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的同學可以看一看。