一、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 中,形参依然是实参的一份临时拷贝。但情况又有不同,因为栈区存放的局部变量对应的地址,我们无法获得,所以我们只能通过数组改变堆区上的某个值,这样一来,也可以完成交换的逻辑。而数组本身就是一个引用类型,这样一来,就是和地址有关联了。