C語言:值傳遞,地址傳遞和引用傳遞(example:值交換)


於C語言中值傳遞、地址傳遞和引用傳遞的我個人理解。

通過一個例子:swap(交換兩個整型變量的值)來表現!

 1 #include <stdio.h>
 2 void swap1(int* a,int* b);
 3 void swap2(int& a,int& b);
 4 void swap3(int* a,int* b);
 5 
 6 void main(){
 7     printf("Hello World!\n");
 8     int a = 3;
 9     int b = 4;
10     printf("bef swap, add of a = %d\n",&a);
11     printf("aft swap, val of a = %d\n",a);
12     //swap(a,b);
13     swap1(&a,&b);
14     //swap2(a,b);
15     //swap3(&a,&b);
16     
17     printf("aft swap, add of a = %d\n",&a);
18     printf("aft swap, val of a = %d\n",a);
19 }
20 // pass by value
21 void swap(int a,int b){
22     int temp = a;
23     a = b;
24     b = temp;
25 }
26 // pass by address
27 void swap1(int* a,int *b){
28     int temp = *a;
29     *a = *b;
30     *b = temp;
31 }
32 // pass by reference
33 void swap2(int& a,int& b){
34     int temp = a;
35     a = b;
36     b = temp;
37 }
38 // pass by value ?
39 void swap3(int* a,int *b){
40     int* temp = a;
41     a = b;
42     b = temp;
43 }

上面的函數,四個swap函數,輸出結果:

swap(a,b):

swap1(a,b):

 

swap2(a,b):

 

swap3(a,b):

 

我們看到,真正起作用的是swap1和swap2.這兩個分別是地址傳遞和引用傳遞。swap是典型的值傳遞,swap3是什么我后面會講。

分析!

0,值傳遞

  這個比較簡單,實參a 原本指向地址 1638212,代表1638212這個地址的值是3。在swap函數中,實參a將值拷貝給形參a,形參a此時也在內存中擁有地址,地址= xxxx,值為3,在所有的函數體內的操作,都是對 xxxx這個地址的操作,所以並不會影響實際參數的值。

1,地址傳遞

  這個對於理不清指針是什么的同學來說比較難。在這里我們習慣把指針寫成int* a,int* b而不是int *a,int *b。我們可以這樣理解:指針是一種特殊的數據類型,若 int c = 5;int* a = &c;則a是一個指針變量,它的值是c的地址!星號“*”是一個取值操作,和號“&”是一個取址操作。所以此時單純看a和b都是一個整數,它們表示地址,進行取值操作之后就可以得到相應地址的值。函數接受兩個類型為指針的變量,實際接受的是a和b,即兩個地址。所以現在分析函數體:

1 int temp = *a;//取出地址a的值,並賦值給整型變量temp
2 *a = *b;      //取出地址b的值,並將這個值賦給地址a指向的值
3 *b = temp;    //將temp的值賦給地址b所指向的值

  因此,我們看到,由於函數傳入的是地址,而函數體內又對地址進行取值和賦值操作,所以相對應的地址的值發生了改變。但是地址並沒有實際改變,從函數的輸出來看,a的地址並不會改變。在C語言中,函數在運行的時候會對每個變量分配內存地址,分配之后只要變量不被銷毀,這個地址不能改變。&a = &b;是無法編譯通過的。

2,引用傳遞

  這個理解起來更簡單,我們這樣理解引用,引用是變量的一個別名,調用這個別名和調用這個變量是完全一樣的。所以swap2的結果可以解釋。值得注意的是,由於引用時別名,所以引用並不是一種數據類型,內存並不會給它單獨分配內存,而是直接調用它所引用的變量。這個與地址傳遞也就是指針是不一樣的(也就是說一個指針雖然指向一個變量,但是這個指針變量在內存中是有地址分配的),下面代碼進行驗證。

 1 void main(){
 2     printf("Hello World!\n");
 3     int a = 3;
 4     int b = 4;
 5     int* c = &a;//c是指向a的指針
 6     int& d = b;//d是b的引用,alias of b = d
 7     printf("val of a = %d\n",a);
 8     printf("add of a = %d\n",&a);
 9     printf("val of c = %d\n",c);
10     printf("add of c = %d\n",&c);
11     printf("val of b = %d\n",b);
12     printf("add of b = %d\n",&b);
13     printf("val of d = %d\n",d);
14     printf("add of d = %d\n",&d);
15 }

輸出結果:

我們看到c的值是a的地址,c的地址是單獨分配的;而d的值是b的值,d的地址是b的地址!

4,關於swap3怎么解釋。

我認為swap3是一種值傳遞,如果我們把int*完全當做跟int一個級別的數據類型,那么swap3和swap兩個函數是一摸一樣的。只不過后者傳入的是變量a,b的拷貝值,而后者傳入的是變量a,b的地址的拷貝值;前者不能反應在外部,后者也不能。

最后,我們注意,對於應用,如果我們有代碼:int a = 3; int& b = a;(b is an alias of a)b = 10;那么我們會發現a的值此時也變成了10。

但是在java中,如果我們把java的引用簡單想象成這里的引用,是有問題的。因為如果一個函數出入一個對象Person person = new Person("ZHANG San"),而在函數體內進行這個操作:person = new Person("LI Si");那么person的值並不能被改變,所以我們說java的函數傳遞都是值傳遞。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM