形参&实参,传值调用&引用调用

引言

相信很多C语言初学者都知道形参实参的概念,但在函数调用中,仍然还有很多人会混淆,本文将借助示例代码详细解释C语言中形参实参及传值调用和引用调用。

形参&实参

函数调用中存在两类参数:形式参数及实际参数,两类参数的功能和使用甚至所占空间都不尽相同。下面本文将解释二者的异同。

什么是形参

形式参数(formal parameter),简称形参,是在函数头括号内声明的,某一函数私有的局部变量,。在函数外部中同名变量不会与之冲突。每次调用函数,会对函数头内定义的形参赋值。

如何声明带形参的函数

在使用ANSI C形式声明函数原型:

void function( char a, int b);

当函数接受参数时,函数原型用逗号分隔的列表指明参数的数量和类型。

什么是实参

实际参数(actual argument),简称实参,它是**主调函数(calling function)赋给被调函数(called function)**的具体值。它可以是常量,变量,正确的表达式,甚至是函数。但无论如何实参必须有一个具体的值以供拷贝于形参之中。

二者关系

简而言之,形参实际上是一种“空白”或是一种“占位符”,在函数调用的过程中,我们在某一已定义的函数中的括号内使用实参,此后函数将会拷贝实参至函数体内“填充”形参,并在函数体内得到使用。
至于怎样使用,本文将在后续段落进行详细描述。

传值调用&引用调用

实参的传递过程有两种不同的机制,其分别是传值调用和引用调用。

传值调用

传值调用的定义

在传值调用过程中,形参是一个局部变量,其初值为调用函数是括号内赋予的实参的值。其只是使用了实参的值,在程序运行时,其在函数体内占用另外的内存空间,不对实参造成影响。

传值调用的代码实例

#include<stdio.h>
int fun1(int a,int b){
	a=2;
	b=2;
}
int main(){
	int i=0;
	int j=0;
	printf("before change:\ni=%d,j=%d\n",i,j);
	fun1(i,j);
	printf("after change:\ni=%d,j=%d\n",i,j);   
	}

其运行结果如下:

我们发现,果然,传值调用中对形参的操作不会对实参造成影响。

引用调用

引用调用的定义

在引用调用过程中,形参传递的不再只是一个值或是一个简单的结果,而是传递实参的地址。虽然形参仍然是一个占位符或是一个空白,但将实参拷贝到形参上后,它不再如传值调用一样占用额外的内存空间,而是和实参占用同一个内存空间。发生在形参上的任何改变都将与此同时体现在实参上。

引用调用的代码实例

实例1:

 #include<stdio.h>
 int fun3(int *a,int *b){
	int m,*c;
	m=0;
	c=&m;
	*c=*a;
	*a=*b;
	*b=*c;
}
 int main(){
	int *p,*q,s,t;
	s=11;
	t=24;
	p=&s;
	q=&t;
	printf("before change:\ns=%d,t=%d\n",*p,*q);
	fun3(p,q);
	printf("after change:\ns=%d,t=%d\n",*p,*q); 
} 

其运行结果如下:
在这里插入图片描述
在此例中,我们调用函数时代入的实参分别是s和t的地址,因此发生引用调用,在函数中对s和t进行交换后,实参s和t的值同时也被交换。
实例2:

#include<stdio.h>
#define N 4
int fun3(int *a){
	int i;
	for (i=0;i<N;i++){
		a[i]=0;
	}
}
int main(){   
	int i;  
	int m[]={1,2,3,4};
	printf("before change:\nm[4]=");
	for (i=0;i<N;i++){
		printf("%d ",m[i]);   
		}
		printf("\n");
	fun3(m); 							/*此时的m是一个数组名,同时也是数组m第一个值m[0]的地址,此时发生引用调用*/ 
	printf("after change:\nm[4]=");                
	for (i=0;i<N;i++){
		printf("%d ",m[i]);   
		}
	printf("\n");
	} 

其运行结果如下:
在这里插入图片描述
我们可以清晰地看见实参数组m的值在函数内部发生了变化。

猜你喜欢

转载自blog.csdn.net/qq_40013374/article/details/88679721