于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的函数传递都是值传递。