首页 > 编程笔记 > C语言笔记 阅读:43

C语言指针作为函数参数(非常详细)

先看一个实例,它使用 swap() 函数交换两个变量的值:
#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

可以看出,变量 a 在内存中的地址为 6487580,变量 b 在内存中的地址为 6487576,变量 x 在内存中的地址为 6487536,变量 y 在内存中的地址为 6487544。

很明显,这四个变量在内存中的地址是完全不同的。当我们调用 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

可以看出,变量 a 和 b 的值被成功地交换了。

与前面的例子相比,这个版本的 swap() 函数使用了指针参数,而不是基础类型参数。这使得我们能够直接访问并修改原始变量 a 和 b 的值,从而实现了正确的值交换。

在前面的例子中,由于使用了基础类型参数,swap() 函数只能交换局部变量 x 和 y 的值,而不影响原始变量 a 和 b 的值。这是这两个例子之间的主要区别。

现在,我们终于能解释为什么在使用 scanf() 函数时,需要对变量先取地址再传入参数了。
int n;
scanf("%d", &n);
这是因为被调函数 scanf() 无法直接修改在主调函数中的变量 n。因此,我们将变量 n 的指针传递给 scanf() 函数,并通过指针间接地修改主调函数中的变量,从而实现了修改变量的值。

相关文章