C语言指针作为函数参数(非常详细)
先看一个实例,它使用 swap() 函数交换两个变量的值:
现在,我们使用取地址运算符(&)来获取变量的地址,并分别输出 swap() 函数和 main() 函数中变量的地址,从内存的角度来分析无法使用 swap() 函数交换的原因。具体代码如下:
很明显,这四个变量在内存中的地址是完全不同的。当我们调用 swap(a, b) 时,我们只是将 a 和 b 的值复制到 swap() 函数的变量 x 和 y 中,它们在内存中的地址不会发生任何变化。
因此,无论如何交换 swap() 函数中 x 和 y 的值,实际上并不会影响 main() 函数中的变量 a 和 b 的值。
下图形象地展示了 swap() 函数无法交换变量 a 和 b 的值的原因。图片中有四个盒子,标签分别为 a、b、x 和 y。

图 1 盒子举例
在这个例子中,a 和 b 盒子代表 main() 函数中的变量,x 和 y 盒子代表 swap() 函数中的变量。当我们尝试使用 swap() 函数交换变量 a 和 b 的值时,这个过程可以想象成将 a 和 b 盒子中的物品复制到 x 和 y 盒子中。
在 swap() 函数内部,我们尝试交换 x 和 y 盒子中的物品。然而,这并不会影响原始的 a 和 b 盒子中的物品,因为这两组盒子是独立的,它们之间并没有直接的联系。因此,尽管我们在 swap() 函数中交换了 x 和 y 盒子中的物品,但 main() 函数中 a 和 b 盒子中的物品仍然保持不变。
因此,我们可以在函数 main() 中获取变量 a 和 b 的指针,并将这两个指针传递给函数 swap()。在函数 swap() 内部,根据这两个指针间接修改变量 a 和 b 的值,实现了交换变量的值。
根据上述的方法,我们修改了代码:
注意,不是交换指针 x 和 y 的值,而是交换指针 x 和 y 所指向的目标数据对象 a 和 b 的值。因此,需要在指针前使用取值运算符(*)。
程序的运行结果为:
与前面的例子相比,这个版本的 swap() 函数使用了指针参数,而不是基础类型参数。这使得我们能够直接访问并修改原始变量 a 和 b 的值,从而实现了正确的值交换。
在前面的例子中,由于使用了基础类型参数,swap() 函数只能交换局部变量 x 和 y 的值,而不影响原始变量 a 和 b 的值。这是这两个例子之间的主要区别。
现在,我们终于能解释为什么在使用 scanf() 函数时,需要对变量先取地址再传入参数了。
#include <stdio.h> void swap(int x, int y) { int temp = x; x = y; y = temp; } int main() { int a, b; a = 1; b = 2; printf("a=%d b=%d\n", a, b); // 交换变量 a 和 b swap(a, b); printf("a=%d b=%d\n", a, b); return 0; }函数 swap() 无论怎样修改变量 x 和 y 的值,都不会影响主调函数中的变量 a 和 b。
现在,我们使用取地址运算符(&)来获取变量的地址,并分别输出 swap() 函数和 main() 函数中变量的地址,从内存的角度来分析无法使用 swap() 函数交换的原因。具体代码如下:
#include <stdio.h> void swap(int x, int y) { // 输出 x、y 的首地址 printf("&x= %llu\n", (unsigned long long)&x); printf("&y= %llu\n", (unsigned long long)&y); int temp = x; x = y; y = temp; } int main() { int a, b; a = 1; b = 2; // 输出 a、b 的首地址 printf("&a= %llu\n", (unsigned long long)&a); printf("&b= %llu\n", (unsigned long long)&b); // 交换变量 a、b swap(a, b); printf("a=%d b=%d\n", a, b); return 0; }运行结果为:
&a= 6487580
&b= 6487576
&x= 6487536
&y= 6487544
a=1 b=2
很明显,这四个变量在内存中的地址是完全不同的。当我们调用 swap(a, b) 时,我们只是将 a 和 b 的值复制到 swap() 函数的变量 x 和 y 中,它们在内存中的地址不会发生任何变化。
因此,无论如何交换 swap() 函数中 x 和 y 的值,实际上并不会影响 main() 函数中的变量 a 和 b 的值。
下图形象地展示了 swap() 函数无法交换变量 a 和 b 的值的原因。图片中有四个盒子,标签分别为 a、b、x 和 y。

图 1 盒子举例
在这个例子中,a 和 b 盒子代表 main() 函数中的变量,x 和 y 盒子代表 swap() 函数中的变量。当我们尝试使用 swap() 函数交换变量 a 和 b 的值时,这个过程可以想象成将 a 和 b 盒子中的物品复制到 x 和 y 盒子中。
在 swap() 函数内部,我们尝试交换 x 和 y 盒子中的物品。然而,这并不会影响原始的 a 和 b 盒子中的物品,因为这两组盒子是独立的,它们之间并没有直接的联系。因此,尽管我们在 swap() 函数中交换了 x 和 y 盒子中的物品,但 main() 函数中 a 和 b 盒子中的物品仍然保持不变。
将指针作为函数参数
前面解释了变量 a 和 b 与变量 x 和 y 的内存地址不同,因此它们相互独立,互不影响。那么我们可否采用迂回战术,让变量 x 的内存地址变成变量 a 的内存地址,让变量 y 的内存地址变成变量 b 的内存地址,这样修改变量 x 和 y 就相当于直接修改了变量 a 和 b。因此,我们可以在函数 main() 中获取变量 a 和 b 的指针,并将这两个指针传递给函数 swap()。在函数 swap() 内部,根据这两个指针间接修改变量 a 和 b 的值,实现了交换变量的值。
根据上述的方法,我们修改了代码:
#include <stdio.h> void swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; } int main() { int a, b; a = 1; b = 2; printf("a=%d b=%d\n", a, b); // 交换变量 a 和 b swap(&a, &b); printf("a=%d b=%d\n", a, b); return 0; }在这段代码中,将函数 swap() 的参数 x 和 y 改为指针类型,并在主调函数 main() 中对变量 a 和 b 进行取地址获取指针,并将这两个指针传递给函数 swap()。在函数 swap() 内部,通过这两个指针间接修改变量 a 和 b 的值,实现了交换变量的值。
注意,不是交换指针 x 和 y 的值,而是交换指针 x 和 y 所指向的目标数据对象 a 和 b 的值。因此,需要在指针前使用取值运算符(*)。
程序的运行结果为:
a=1 b=2
a=2 b=1
与前面的例子相比,这个版本的 swap() 函数使用了指针参数,而不是基础类型参数。这使得我们能够直接访问并修改原始变量 a 和 b 的值,从而实现了正确的值交换。
在前面的例子中,由于使用了基础类型参数,swap() 函数只能交换局部变量 x 和 y 的值,而不影响原始变量 a 和 b 的值。这是这两个例子之间的主要区别。
现在,我们终于能解释为什么在使用 scanf() 函数时,需要对变量先取地址再传入参数了。
int n; scanf("%d", &n);这是因为被调函数 scanf() 无法直接修改在主调函数中的变量 n。因此,我们将变量 n 的指针传递给 scanf() 函数,并通过指针间接地修改主调函数中的变量,从而实现了修改变量的值。