一、C语言
程序清单1
#include <stdio.h>
void swap(int x, int y) {
int tmp = x;
x = y;
y = tmp;
}
int main() {
int a = 3;
int b = 5;
printf("a = %d b = %d\n", a, b);
swap(a, b);
printf("a = %d b = %d\n", a, b);
return 0;
}
输出结果:
分析:
在程序清单1中,a, b 为实参,x, y 为形参。
当 a 和 b 传入 swap( ) 函数的时候,x 和 y 确实能拿到 3 和 5 这两个值,但 x 和 y 本身与 a 和 b 拥有不同的地址,这就造成一个结果:在swap() 函数中,只交换了形参 x 和 y 的值,对于实参 a 和 b 来说,毫无影响。
程序清单2
#include <stdio.h>
void swap(int* pa, int* pb) {
int tmp = *pa; // 解引用
*pa = *pb;
*pb = tmp;
}
int main() {
int a = 3;
int b = 5;
printf("a = %d b = %d\n", a, b);
swap(&a, &b);
printf("a = %d b = %d\n", a, b);
return 0;
}
输出结果:
分析:
在程序清单2 中,当我们实参传的是 a 和 b 的地址时,情况就完全不一样了,在 swap( ) 函数中,我们形参拿整型指针类型来接收地址,最后再通过解引用符号 " * " 来拿到地址对应的值,即可交换。
这里需要注意: pa 和 pb 存的值是 a 和 b 的地址,然而 pa 和 pb 本身是一个指针变量,既然是变量,它们也有属于自己的地址,前者后者不能搞混了。
二、Java
程序清单3
public class Test {
public static void main(String[] args) {
int a = 3;
int b = 5;
System.out.println("a = " + a + " b = " + b);
swap(a,b);
System.out.println("a = " + a + " b = " + b);
}
public static void swap(int a, int b){
int temp = a;
a = b;
b = temp;
}
}
输出结果:
在程序清单3中,现在我们就可以理解了 swap() 函数中的 a 和 b 和 main 函数中的 a 和 b 是不一样的。
程序清单4
public class Test {
public static void main(String[] args) {
int[] arr = {3, 5};
System.out.println("a = " + arr[0] + " b = " + arr[1]);
swap(arr);
System.out.println("a = " + arr[0] + " b = " + arr[1]);
}
public static void swap(int[] arr) {
int tmp = arr[0];
arr[0] = arr[1];
arr[1] = tmp;
}
}
输出结果:
在 Java 中,我们拿不到局部变量的地址,或者说是拿不到栈区的地址。所以在程序清单4中,如果想要利用函数进行交换值,我们只能通过改变堆区的值来进行交换。
三、总结
① 形参是实参的一份临时拷贝,其只在当前函数中有效,出了当前函数,即被销毁,所以改变形参本质上不会影响实参的状态。
② 在 C 语言中,我们可以利用指针接收地址,从而拿到地址对应的值来直接进行改变实参。
③ 在 Java 中,形参依然是实参的一份临时拷贝。但情况又有不同,因为栈区存放的局部变量对应的地址,我们无法获得,所以我们只能通过数组改变堆区上的某个值,这样一来,也可以完成交换的逻辑。而数组本身就是一个引用类型,这样一来,就是和地址有关联了。