6.1.4 函数的参数
函数的参数是指主调函数与被调函数间进行的数据交换时所依赖的媒介。函数的参数是函数部分相当重要的内容。函数的参数包括形参和实参两种。在C51中,函数的参数可以采用多种数据类型,例如整型、字符型、浮点型,甚至可以是指针、数组以及多维数组等。下面就分别介绍参数的相关内容。
1.形参和实参
函数的参数可以分为形参和实参两种。主调函数中的参数称为“实参”;被调函数中的参数称为“形参”。在函数调用过程中,主调函数把实参的值传递给被调函数的形参,从而实现主调函数向被调函数的数据传送。最后被调函数再将函数返回值传递给主调函数,这样就实现了函数间的调用。
在程序中使用函数的形参和实参时,应注意以下几点。
❑实参可以是常量、变量、表达式等。无论实参是何种类型的数据,在进行函数调用时,都必须先给实参赋值,在函数调用过程中,将其值传递给形参。实参定义在主调函数中,当其值进入被调函数后,主调函数中的实参将不再被使用。
❑形参只有在被调函数内部才有效。形参变量只有在被调用时系统才为其分配内存空间,调用结束后,其所分配的内存空间将立即释放。因此在函数调用结束返回主调函数后,就不能再使用该形参变量了。
❑实参和形参在数量、类型和顺序上应严格保持一致,否则会因类型不匹配而导致错误。
❑在函数调用过程中,由实参单向地向形参进行数据传送,不能将形参的值反向地传递给实参。因此形参的值在函数调用过程中会发生改变,而实参的值将不发生变化。
形参和实参在函数调用过程中的程序示例如下。
include<stdio.h>//头文件
void sum(int n);//自定义函数声明
void main()//主函数
{
int n=5;//定义并初始化变量
sum(n);//调用sum函数
printf(“in the main function n=%d\n”,n);//输出main主函数中的n
}
void sum(int n)//函数定义
{
int i;//定义变量
for(i=n-1;i>=1;i—)//for循环计算累加值
n=n+i;//累加的结果赋值给n
printf(“in the sum function n=%d\n”,n);//输出sum函数中n的值
}
该程序可以在KeilµVision3编译环境中执行,运行的结果如下。
in the sum function n=15
in the main function n=5
在本例中,定义了函数sum和形参n,用于计算从1到n所有正整数之和。在主函数中定义并初始化实参n=5。本例的形参和实参的标识符都为n,但这是两个含义不同的量,具有不同的变量作用域。从程序结果可以看出,实参作用域为main函数,其值不随形参变化。而形参的值只在自定义函数内才有效。
2.指针作为函数参数
指针作为函数参数是指在发生函数调用时,把指针变量的值作为实参传送给形参,实现单向的值传送。使用指针类型作为函数的参数,实际向函数传递的是地址值。指针作为函数参数的程序示例如下。
include<stdio.h>//头文件
void change(char*c)//自定义函数声明
void main()//主函数
{
char*c;//定义字符型指针变量
*c=‘q’;//赋值
change(c);//调用函数
printf(“The char is%c”,*c);//输出结果
}
void change(char*c)//定义函数,用于将小写字符改为大写字符
{
if(c>=‘a'&c<='z’)//判断,如果为小写,则转换为大写
c=c-32;
}
该程序可以在KeilµVision3编译环境中执行,运行的结果如下。
The char is Q
在本例中,定义了函数change(),用于将小写字符改为相应的大写字符。程序中的实参和形参都是字符型指针变量。在函数调用过程中,将实参指针c的地址作为实参的值传给形参。change()函数对该地址中的数据进行操作,因此该地址所对应的变量值改变了。从而达到将小写字符改为大写字符的目的。
注意由于函数调用过程中,传递的是变量的地址,因此当函数调用结束后,该地址中的数据已经改变,但是主调函数中的实参值不变,即变量的地址并不发生改变,但是其地址中的值发生了改变。
3.数组作为函数参数
数组可以作为函数的参数使用,进行数据传送。在C51语言中,数组用作函数参数有两种情况,一种是把数组元素作为函数的参数使用;另一种是把数组名作为函数的参数使用。
❑数组元素作为实参
数组元素就是下标变量,与普通变量的使用是完全相同的。因此,数组元素可作为函数实参使用。当数组元素作为函数实参时,在函数调用过程中,把定义为实参的数组元素的值传递给形参。
数组元素作函数实参的程序示例如下。
include<stdio.h>//头文件
void fun(int x)//自定义函数
{
if(x%2==0)//判断是否为偶数
printf(“%d\n”,x);//如果是则输出
}
void main()//主函数
{
int i;
int num[6]={1,2,3,4,5,6};//定义并初始化数组
for(i=0;i<6;i++)//循环调用函数
{
fun(num[i]);
}
}
该程序可以在KeilµVision3编译环境中执行,运行的结果如下。
2
4
6
在本例中,定义了函数fun(),用于判别一个整数数组中各元素的值的奇偶性,若是偶数则输出该值,否则不输出。函数fun()是无返回值函数,其形参x为整型。函数体中根据x值判断并输出相应的结果。在主函数中,定义并初始化一个整型数组num[6],然后用for循环调用自定义的fun()函数,即把数组num的元素的值依序传递给形参,经fun()函数处理后,打印并输出结果。
❑数组名作为实参
数组名可以作为函数实参和形参使用。当数组名作函数参数时,不是把定义为实参的数组的每一个元素的值都赋予形参数组的各个元素,而是将实参数组的首地址传递给形参数组名,这和前面介绍的指针作为函数参数的情况类似。实际上是形参数组和实参数组为同一数组,共同拥有一段内存空间。在普通变量或数组元素作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元。在函数调用过程中,只是把实参变量的值传递给形参变量。
注意用数组元素作为函数实参时,要求数组元素的类型和函数的形参变量的类型一致,但并不要求函数的形参也是数组元素,即下标变量。但用数组名作实参时,则要求形参和实参都是类型相同的数组,都必须进行明确的声明。若形参和实参二者类型不一致或不都是数组时,程序会发生不可预测的错误。
数组名作为函数参数的程序示例如下。
include<stdio.h>//头文件
int sum(int num[6])//自定义函数,用于求和
{
int i;
int sum=0;
for(i=0;i<6;i++)//循环求和
sum=sum+num[i];
return sum;
}
void main()//主函数
{
int num[6]={1,2,3,4,5,6};//定义并初始化数组
printf(“1+2+3+4+5+6=%d\n”,sum(num));//调用函数,输出结果
}
该程序可以在KeilµVision3编译环境中执行,运行的结果如下。
1+2+3+4+5+6=21
本例中,先定义了函数sum(),其形参为长度为5的整型数组num。其函数体中,采用for循环将各元素值相加求和,并将结果返回给主函数。主函数中定义并初始化实参数组num,用于存放6个数1~6,然后调用sum()函数,将实参数组num传递给形参数组num,最后打印并输出结果。
4.多维数组作为函数参数
和一维数组一样,多维数组也可以作为函数的参数。可以将多维数组的数组元素或者数组名作为参数进行传递。以二维数组名作为参数的情况示例如下。
int sum(int a[5][6])
本例定义一个大小为5×6的二维数组a作为函数sum的形参变量。
在C51语言中定义函数时,对形参数组可以明确指定每一维的长度,也可省去第一维的长度,形式如下。
int sum(int a[][6])//合法的
多维数组作为函数参数的程序示例如下。
include<stdio.h>//头文件
int sum(int num[5][6])//声明自定义函数
void main()//主函数
{
int sum1;//定义并初始化二维数组
int num[5][6]={{10,11,12,0,1,1},{7,8,9,1,1,1},{4,5,6,4,5,6},{1,2,3,1,2,3},{0,1,1,1,0,1}};
sum1=sum(num);//调用函数
printf(“the sum of num[5][6]is%d\n”,sum1);//输出结果
}
int sum(int num[5][6])//定义函数
{
int i,j;
int sum=0;
for(i=0;i<5;i++)//循环累加数组元素
{
for(j=0;j<6;j++)
sum=sum+num[i][j];
}
return sum;//返回累加值
}
该程序可以在KeilµVision3编译环境中执行,运行的结果如下。
the sum of num[5][6]is 108
在本例中,定义了函数sum,其形参为二维整型数组num[5][6],用于求数组中每个元素的和并返回。在主函数中,声明并初始化一个二维整型数组num[5][6],调用函数sum,以数组名作为实参,将数组首地址传递给函数sum的形参变量,函数sum将计算结果返回主函数,最后输出结果。