在前面学习函数时,曾学习过函数的参数。函数的参数可以是具体的值,也可以是变量。当函数的参数是变量时,就涉及到参数如何传递到函数中。一般有两种方式:传值引用方式、传址引用方式。
一、传值引用:函数的参数以变量方式传入函数时,实际传入的是这个变量的值拷贝,而不是变量本身。这种使用参数的方式称为传值引用。举例看一下:
#include<stdio.h>
void func (int x)
{
x = 2 * x; //将传入的x做乘以2运算后再赋值给x
printf("func函数中x=%d\n", x);
//将经过函数计算的x显示到屏幕上。运行结果:func函数中x=10
}
int main(void)
{
int x = 5;
func(x); //将参数x传入func函数
printf("主函数中x=%d\n", x); //运行结果:主函数中x=5
getchar();
return 0;
}
从子函数 func 函数的运行结果看,x已在子函数中被乘以2变成了10;但我们从主函数调用func完毕后的位置看 x 的值,仍然是开始的5而不是10。这说明,x以变量方式传入函数func后,无论经过怎样的计算,都不会影响到x原来的值。相当于是 x 找了一个替身(拷贝)把值 5 传入了函数func,自己仍躲在外边没到函数中去。
从上面的内容看传值方式的好处是,不管有多少函数使用某一变量的值进行运算,都不会影响到变量的原值。但有时,我们就希望把传入的参数的值给改一下,怎么做呢?可以把 func 函数给改一下,无返回值的 void 类型改成有返回值的 int 类型,然后用 x 接收函数的返回值,这样 x 的值就改变了(举例略)。但一个函数的返回值只能有一个,如果有多个参数需要改变时,就不好办了,怎么办呢好呢?这就引出下一种参数传递方式。
二、传址引用:通过传入变量的地址,函数内部就可以直接操作该地址,该地址存储的值进而改变。表面上看,只是通过传参将变量地址传入函数,并没有通过返回值将参数返回,但客观上原参数变量的值确实被改变了。举例如下:
#include<stdio.h>
void func1 (int* x,int* y) //以传址方式传参的无返回值函数
{
// 以上三个语句将x、y的值进行了交换
int temp = *x;
*x = *y;
*y = temp;
//将经过函数计算的x、y显示到屏幕上
printf("func1运行中:*x=%d,*y=%d\n", *x,*y);
}
int main(void)
{
int a = 5,b=10; //记住两个变量a和b的原值
printf("func1运行前:原参数a=%d,b=%d\n", a, b);
int* x = &a; //把a的地址赋给x
int* y = &b; //把b的地址赋给y
func1(x,y); //运行函数func1并把a、b的地址作为参数传到函数中
printf("func1运行后:原参数a=%d,b=%d\n", a, b);
getchar();
return 0;
}
运行结果:
func1运行前:原参数a=5,b=10
func1运行中:*x=10,*y=5
func1运行后:原参数a=10,b=5
上面程序的将原始的变量a、b的地址作为参数传入func1函数,函数运行将两个地址上的值进行了交换,函数运行后,我们发现a、b的值进行了交换。这就是参数变量传址方式的结果。
总结:如只需要利用参数变量的值进行计算后输出一个结果,就利用传值方式传递参数;如需要把参数变量的值进行改变并在其它地方使用这些值,使用传址方式传递参数为佳;传值、传址两种方式结合起来效果更好。
另外,如果声明一个返回值为指针类型的函数,要注意返回指针变量的作用域。如在函数内部声明的指针,传到函数外时,由于函数运行已经结束,占用的地址空间都被系统收回了,这时再使用那个指针肯定要出错。(可以使用全局指针变量)