目录
函数的参数
实际参数(实参)
实参:真实传给函数的参数。
实参可以是:常量、变量、表达式、函数等。(无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传给形参)
例子:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//函数实现交换两数的值
void exch(int* pa, int* pb)//函数括号后面的参数名称也可以和传过来的参数重名
//也可以写成 void exch(int *a,int *b)
{
int tmp = 0;
tmp = *pa;
*pa = *pb;
*pb = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
exch(&a,&b);
printf("%d %d\n",a,b);
return 0;
}
代码解释:此代码目的是为了交换两个数的值,在主函数中定义两个变量,函数exch中实现交换两数的值,通过传址传参将主函数中定义的两个变量传给函数exch(实际就是把主函数中定义的两个变量的地址交给函数exch)。
exch(&a, &b);//&是取地址操作符,意思是把a、b的地址取出来交给函数exch
//同时定义exch函数时也要有对应的接收
void exch(int* pa, int* pb)//因为a和b是是两个整型数字,所以定义两个整型变量指针,即int *
//pa是接收a变量的地址,即pa=&a
//*是间接访问操作符(解引用操作符),即*pa=a
//pb、b同理
佐证:
形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只有在对应的函数中有效。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//交换两数的值
void exch(int x, int y)//这里我是为了后面监视对象时有所区分,所以写成(int x, int y)不同的名称
//其实参数名称无所谓,也可以与传过来的参数名称相同,例如:void exch(int a, int b)
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
exch(a,b);//把a,b两个参数传过去,实参与形参的名字是什么无所谓,这里才是关键
printf("%d %d\n",a,b);
return 0;
}
此代码目的是为了交换两个数的值,在主函数中定义两个变量,函数exch中实现交换两数的值,通过传值传参将主函数中定义的两个变量传给函数exch,那么这个代码能实现我的目的吗?如下:
显然是没有实现的。那么我们就来看看,同样是传参,传址传参和传值传参有什么不同?在传址传参的代码分析中,我们看到了将a、b两个参数的地址传到函数exch中,用两个整型变量指针分别接收 a、b的地址,因此才有在函数exch中改变a、b的值,在主函数中打印a、b的值时,a、b的值也发生了改变。
这里我们看一下传值传参方式中各个变量的地址,如下:
在调用函数x、y时,x、y已经有了自己的空间,同时有了和实参一样的内容。所以我们可以简单理解为:形参实例化之后其实相当于实参的一份临时拷贝。形参是是实参的一份临时拷贝!!!
函数的调用
通过上述内容以及代码,就能理解对于参数的两种调用方式:传址调用和传值调用
传址调用
- 传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式
- 这种传参方式可以让函数和函数外面的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量
传值调用
- 函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参
至于什么时候使用传址调用,什么时候使用传值调用,就需要根据自己的目的来采用合适的函数调用方式。例如,如果需要在函数内部改变两数的值,就需要采用传址调用。如果不需要在函数内部改变参数的值,可以根据自己的偏好决定。