於C語言中值傳遞、地址傳遞和引用傳遞的我我的理解。java
經過一個例子: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函數,輸出結果:spa
swap(a,b):指針
swap1(a,b):code
swap2(a,b):對象
swap3(a,b):blog
咱們看到,真正起做用的是swap1和swap2.這兩個分別是地址傳遞和引用傳遞。swap是典型的值傳遞,swap3是什麼我後面會講。內存
分析!io
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的函數傳遞都是值傳遞。