AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > C语言

C语言入门之函数(2)

51自学网 2015-09-08 http://www.51zixue.net

   一、函数的参数

   前面已经介绍过,函数的参数分为形参和实参两种。 在本小节中,进一步介绍形参、实参的特点和两者的关系。 形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。 形参和实参的功能是作数据传送。发生函数调用时, 主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。

   函数的形参和实参具有以下特点:

   1.形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。 函数调用结束返回主调函数后则不能再使用该形参变量。

   2.实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。

   3.实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。

   4.函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。例5.3可以说明这个问题。

void main()
{
int n;
printf("input number/n");
scanf("%d",&n);
s(n);
printf("n=%d/n",n);
}
int s(int n)
{
int i;
for(i=n-1;i>=1;i--)
n=n+i;
printf("n=%d/n",n);
}

   本程序中定义了一个函数s,该函数的功能是求∑ni=1i 的值。在主函数中输入n值,并作为实参,在调用时传送给s 函数的形参量n( 注意,本例的形参变量和实参变量的标识符都为n, 但这是两个不同的量,各自的作用域不同)。 在主函数中用printf 语句输出一次n值,这个n值是实参n的值。在函数s中也用printf 语句输出了一次n值,这个n值是形参最后取得的n值0。从运行情况看,输入n值为100。即实参n的值为100。把此值传给函数s时,形参 n 的初值也为100,在执行函数过程中,形参n的值变为5050。 返回主函数之后,输出实参n的值仍为100。可见实参的值不随形参的变化而变化。

   二、函数的值

   函数的值是指函数被调用之后, 执行函数体中的程序段所取得的并返回给主调函数的值。如调用正弦函数取得正弦值,调用例5.1的max函数取得的最大数等。对函数的值(或称函数返回值)有以下一些说明:

   1. 函数的值只能通过return语句返回主调函数。return 语句的一般形式为:

   return 表达式;

   或者为:

   return (表达式);

   该语句的功能是计算表达式的值,并返回给主调函数。 在函数中允许有多个return语句,但每次调用只能有一个return 语句被执行, 因此只能返回一个函数值。

   2. 函数值的类型和函数定义中函数的类型应保持一致。 如果两者不一致,则以函数类型为准,自动进行类型转换。

   3. 如函数值为整型,在函数定义时可以省去类型说明。

   4. 不返回函数值的函数,可以明确定义为“空类型”, 类型说明符为“void”。如例5.3中函数s并不向主函数返函数值,因此可定义为:

void s(int n)
{ ……
}

   一旦函数被定义为空类型后, 就不能在主调函数中使用被调函数的函数值了。例如,在定义s为空类型后,在主函数中写下述语句 sum=s(n); 就是错误的。为了使程序有良好的可读性并减少出错, 凡不要求返回值的函数都应定义为空类型。函数说明在主调函数中调用某函数之前应对该被调函数进行说明, 这与使用变量之前要先进行变量说明是一样的。 在主调函数中对被调函数作说明的目的是使编译系统知道被调函数返回值的类型, 以便在主调函数中按此种类型对返回值作相应的处理。 对被调函数的说明也有两种格式,一种为传统格式,其一般格式为: 类型说明符 被调函数名(); 这种格式只给出函数返回值的类型,被调函数名及一个空括号。

   这种格式由于在括号中没有任何参数信息, 因此不便于编译系统进行错误检查,易于发生错误。另一种为现代格式,其一般形式为:

   类型说明符 被调函数名(类型 形参,类型 形参…);

   或为:

   类型说明符 被调函数名(类型,类型…);

   现代格式的括号内给出了形参的类型和形参名, 或只给出形参类型。这便于编译系统进行检错,以防止可能出现的错误。例5.1 main函数中对max函数的说明若

   用传统格式可写为:

int max();

   用现代格式可写为:

int max(int a,int b);

   或写为:

int max(int,int);

   C语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。

   1. 如果被调函数的返回值是整型或字符型时, 可以不对被调函数作说明,而直接调用。这时系统将自动对被调函数返回值按整型处理。例5.3的主函数中未对函数s作说明而直接调用即属此种情形。

   2. 当被调函数的函数定义出现在主调函数之前时, 在主调函数中也可以不对被调函数再作说明而直接调用。例如例5.1中, 函数max的定义放在main 函数之前,因此可在main函数中省去对 max函数的函数说明int max(int a,int b)。

   3. 如在所有函数定义之前, 在函数外预先说明了各个函数的类型,则在以后的各主调函数中,可不再对被调函数作说明。例如:

char str(int a);
float f(float b);
main()
{
……
}
char str(int a)
{
……
}
float f(float b)
{
……
}

   其中第一,二行对str函数和f函数预先作了说明。 因此在以后各函数中无须对str和f函数再作说明就可直接调用。

   4. 对库函数的调用不需要再作说明, 但必须把该函数的头文件用include命令包含在源文件前部。数组作为函数参数数组可以作为函数的参数使用,进行数据传送。 数组用作函数参数有两种形式,一种是把数组元素(下标变量)作为实参使用; 另一种是把数组名作为函数的形参和实参使用。一、数组元素作函数实参数组元素就是下标变量,它与普通变量并无区别。 因此它作为函数实参使用与普通变量是完全相同的,在发生函数调用时, 把作为实参的数组元素的值传送给形参,实现单向的值传送。例5.4说明了这种情况。[例5.4]判别一个整数数组中各元素的值,若大于0 则输出该值,若小于等于0则输出0值。编程如下:

void nzp(int v)
{
if(v>0)
printf("%d ",v);
else
printf("%d ",0);
}
main()
{
int a[5],i;
printf("input 5 numbers/n");
for(i=0;i<5;i++)
{
scanf("%d",&a[i]);
nzp(a[i]);
}
}void nzp(int v)
{ ……
}
main()
{
int a[5],i;
printf("input 5 numbers/n");
for(i=0;i<5;i++)
{ scanf("%d",&a[i]);
nzp(a[i]);
}
}

   本程序中首先定义一个无返回值函数nzp,并说明其形参v 为整型变量。在函数体中根据v值输出相应的结果。在main函数中用一个for 语句输入数组各元素, 每输入一个就以该元素作实参调用一次nzp函数,即把a[i]的值传送给形参v,供nzp函数使用。

   二、数组名作为函数参数

   用数组名作函数参数与用数组元素作实参有几点不同:

   1. 用数组元素作实参时,只要数组类型和函数的形参变量的类型一致,那么作为下标变量的数组元素的类型也和函数形参变量的类型是一致的。因此, 并不要求函数的形参也是下标变量。 换句话说,对数组元素的处理是按普通变量对待的。用数组名作函数参数时, 则要求形参和相对应的实参都必须是类型相同的数组,都必须有明确的数组说明。当形参和实参二者不一致时,即会发生错误。

   2. 在普通变量或下标变量作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元。在函数调用时发生的值传送是把实参变量的值赋予形参变量。在用数组名作函数参数时,不是进行值的传送,即不是把实参数组的每一个元素的值都赋予形参数组的各个元素。因为实际上形参数组并不存在,编译系统不为形参数组分配内存。那么,数据的传送是如何实现的呢? 在第四章中我们曾介绍过,数组名就是数组的首地址。因此在数组名作函数参数时所进行的传送只是地址的传送, 也就是说把实参数组的首地址赋予形参数组名。形参数组名取得该首地址之后,也就等于有了实在的数组。实际上是形参数组和实参数组为同一数组,共同拥有一段内存空间。图5.1说明了这种情形。图中设a为实参数组,类型为整型。a占有以2000 为首地址的一块内存区。b为形参数组名。当发生函数调用时,进行地址传送, 把实参数 组a的首地址传送给形参数组名b,于是b也取得该地址2000。 于是a,b两数组共同占有以2000 为首地址的一段连续内存单元。从图中还可以看出a和b下标相同的元素实际上也占相同的两个内存单元(整型数组每个元素占二字节)。例如a[0]和b[0]都占用2000和2001单元,当然a[0]等于b[0]。类推则有a[i]等于b[i]。

   [例5.5]数组a中存放了一个学生5门课程的成绩,求平均成绩。float aver(float a[5])

{
int i;
float av,s=a[0];
for(i=1;i<5;i++)
s=s+a[i];
av=s/5;
return av;
}
void main()
{
float sco[5],av;
int i;
printf("/ninput 5 scores:/n");
for(i=0;i<5;i++)
scanf("%f",&sco[i]);
av=aver(sco);
printf("average score is %5.2f",av);
}
float aver(float a[5])
{ ……
}
void main()
{
……
for(i=0;i<5;i++)
scanf("%f",&sco[i]);
av=aver(sco);
……
}

   本程序首先定义了一个实型函数aver,有一个形参为实型数组a,长度为5。在函数aver中,把各元素值相加求出平均值,返回给主函数。主函数main 中首先完成数组sco的输入,然后以sco作为实参调用aver函数,函数返回值送av,最后输出av值。 从运行情况可以看出,程序实现了所要求的功能

<

 

 

 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,51zixue.net不保证资料的完整性。
 
上一篇:C语言入门之函数(3)  下一篇:C语言入门之函数(1)