1.函数调用的一般形式 前面己经说过,在程序中是通过对函数的调用来执行函数体的。对无参函数调用时则无 实际参数表。实际参数表中的参数可以是常数、变量或其它构造类型数据及表达式,各实参之 间用逗号分隔。 C语言中,函数调用的一般形式为: 函数名(实际参数表) 2.函数调用的方式 在C语言中,可以用以下几种方式调用函数: (1)函数表达式:函数作为表达式中的一项出现在表达式中,以函数返回值参与表达 式的运算。这种方式要求函数是有返回值的。例如:z=sum(xy)是一个赋值表达式,把sum的 返回值赋予变量z。 (2)函数语句:函数调用的一般形式加上分号即构成函数语句。例如:Hlo(): sum(xy)都是以函数语句的方式调用函数。 (3)函数实参:函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回 值作为实参进行传送,因此要求该函数必须是有返回值的。例如:printf("%d",sum(Ky)即是 把sum调用的返回值又作为printf函数的实参来使用的。 例如:将代码清单8.4中的部分代码进行修改: 原代码: main( int xv.z: scanf"%d%) z=sum(x.y): printf"z=%dn"z) 修改后代码: main() int x.y scanf"%d%d",&x&y). printf("%dn",sum(x.y).); 3.被调用函数的声明和函数原型 在主调函数中周用某函数之前应付该被调函数讲行声明,这与使用恋量之前要先讲行恋 量说明是一样的。在主调函数中对被调函数作说明的目的是使编译系统知道被调函数返回值 的类型,以便在主调函数中按出种类型对返回情作相应的处理。 其一般形式为: 类型说明符被调函数名(类型形参,类型形参…: 或为:
1.函数调用的一般形式 前面已经说过,在程序中是通过对函数的调用来执行函数体的。对无参函数调用时则无 实际参数表。实际参数表中的参数可以是常数、变量或其它构造类型数据及表达式,各实参之 间用逗号分隔。 C语言中,函数调用的一般形式为: 函数名(实际参数表) 2.函数调用的方式 在C语言中,可以用以下几种方式调用函数: (1)函数表达式:函数作为表达式中的一项出现在表达式中,以函数返回值参与表达 式的运算。这种方式要求函数是有返回值的。例如:z=sum(x,y)是一个赋值表达式,把 sum 的 返回值赋予变量 z。 (2)函数语句:函数调用的一般形式加上分号即构成函数语句。例如:Hello(); sum(x,y);都是以函数语句的方式调用函数。 (3)函数实参:函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回 值作为实参进行传送,因此要求该函数必须是有返回值的。例如:printf("%d",sum(x,y));即是 把 sum 调用的返回值又作为 printf 函数的实参来使用的。 例如:将代码清单 8.4 中的部分代码进行修改: 原代码: main() { int x,y,z; scanf("%d%d",&x,&y); z=sum(x,y); printf("z=%d\n",z); } 修改后代码: main() { int x,y; scanf("%d%d",&x,&y); printf("%d\n", sum(x,y);); } 3.被调用函数的声明和函数原型 在主调函数中调用某函数之前应对该被调函数进行声明,这与使用变量之前要先进行变 量说明是一样的。在主调函数中对被调函数作说明的目的是使编译系统知道被调函数返回值 的类型,以便在主调函数中按此种类型对返回值作相应的处理。 其一般形式为: 类型说明符 被调函数名(类型 形参,类型 形参…); 或为:
类型说明符被调函数名(类型,类型…): 括号内给出了形参的类型和形参名,或只给出形参类型。这便于编译系统进行检错,以 防止可能出现的错误。例如例8.4中代码清单8.5,main函数中对sum函数的说明为: int sum(int a,int b): 或写为 int sum(int int) C语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。 (1)如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调 用。这时系统将自动对被调函数返回值按整型处理。 (2)当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调 数再作说明而直接调用。例如例8.4中代码清单8.4,函数sum的定义放在main函数之前,因 此可在main函数中省去对sum函数的函数说明int sum(inta.intb)。 (3)如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主 调函数中,可不再对被调函数作说明。 8.4函数的特殊调用方式 8.4.1函数的嵌套调用 C语言中各函数之间是平行的,不存在上一级函数和下一级函数的问题。但是C语言允 许在一个函数的定义中出现对另一个函数的调用。这样就出现了函数的嵌套调用。即在被调函 数中又调用其它函数。其关系可表示如图8.2所示。图中表示了两层嵌套的情形。其执行过程 是:执行main函数中调用函数A的语句时,即转去执行函数A,在函数A中调用函数B时, 又转去执行函数B,函数B执行完毕返回函数A的断点继续执行,函数A执行完毕返回 mam函数的断点继续执行。 main函复 调用函数 图82函数嵌套调用示意图 【例8.5】利用函数嵌套实现程序设计,求1!+2!++10!。 算法设计:编写求阶乘的函数fact: 编写求和的函数sum(其中嵌套调用函数fact): 编写主函数(其中调用函数sum): 代码清单8.6: #include "stdio h" int fact(int n)
类型说明符 被调函数名(类型,类型…); 括号内给出了形参的类型和形参名,或只给出形参类型。这便于编译系统进行检错,以 防止可能出现的错误。例如例 8.4 中代码清单 8.5,main 函数中对 sum 函数的说明为: int sum(int a,int b); 或写为: int sum(int,int); C语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。 (1)如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调 用。这时系统将自动对被调函数返回值按整型处理。 (2)当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函 数再作说明而直接调用。例如例 8.4 中代码清单 8.4,函数 sum 的定义放在 main 函数之前,因 此可在 main 函数中省去对 sum 函数的函数说明 int sum(int a,int b)。 (3)如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主 调函数中,可不再对被调函数作说明。 8.4 函数的特殊调用方式 8.4.1 函数的嵌套调用 C语言中各函数之间是平行的,不存在上一级函数和下一级函数的问题。但是C语言允 许在一个函数的定义中出现对另一个函数的调用。这样就出现了函数的嵌套调用。即在被调函 数中又调用其它函数。其关系可表示如图 8.2 所示。图中表示了两层嵌套的情形。其执行过程 是:执行 main 函数中调用函数 A 的语句时,即转去执行函数 A,在函数 A 中调用函数 B 时, 又转去执行函数 B,函数 B 执行完毕返回函数 A 的断点继续执行,函数 A 执行完毕返回 main 函数的断点继续执行。 图 8.2 函数嵌套调用示意图 【例 8.5】利用函数嵌套实现程序设计,求 1!+2!+…+10!。 算法设计:编写求阶乘的函数 fact; 编写求和的函数 sum(其中嵌套调用函数 fact); 编写主函数(其中调用函数 sum); 代码清单 8.6: #include "stdio.h" int fact(int n) main 函数 调用函数 A 结束 函数 A 调用函数 B 函数 B
int fl,i;, for=1:in:it+)) ffi: return f. int sum(int h) int is=0: for(i=1.i<=h;i++) s=s+fact(i), return s: main( int s; s=sum(10): printf"s=%dn",s) 运行结果:3=4037913。 在程序中,函数fact和sum均为整型,都在主函数之前定义,故不必再在主函数中对 fact和sum加以说明。在主程序中,调用函数sum,将实参10传递给形参h,即h=l0。在函数 sum中利用循环结构调用函数fact共l0次,将实参i从1到10传递给形参n,即 n=1,2,3,…,10后,分别返回1!,2!,3!,,10!给函数sum,函数sum对返回 值求和,然后返回结果给函数main后输出。 8.4.2函数的递归调用 一个函数在它的函数体内调用它自身称为递归调用,这种函数称为递归函数。C语言允 许函数的递归调用。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身, 每调用一次就进入新的一层。为了防止递归调用无终止地进行,必须在函数内有终止递归调 用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。下 面举例说明递归调用的执行过程。 【例8.6】利用函数递归调用实现程序设计,求n!。 算法设计:编写求阶乘的函数fact: 判断n=1时,返回值1: 判断n≥2时,函数fact调用n*fact(n-l) ④编写主函数调用函数fact: 调用过程如图8.3所示:
{ int f=1,i; for(i=1;i<=n;i++) f=f*i; return f; } int sum(int h) { int i,s=0; for(i=1;i<=h;i++) s=s+fact(i); return s; } main() { int s; s=sum(10); printf("s=%d\n",s); } 运行结果:s=4037913。 在程序中,函数 fact 和 sum 均为整型,都在主函数之前定义,故不必再在主函数中对 fact 和 sum 加以说明。在主程序中,调用函数 sum,将实参 10 传递给形参 h,即 h=10。在函数 sum 中利用循环结构调用函数 fact 共 10 次,将实参 i 从 1 到 10 传递给形参 n,即 n=1,2,3,…,10 后,分别返回 1!,2!,3!,…,10!给函数 sum,函数 sum 对返回 值求和,然后返回结果给函数 main 后输出。 8.4.2 函数的递归调用 一个函数在它的函数体内调用它自身称为递归调用,这种函数称为递归函数。C语言允 许函数的递归调用。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身, 每调用一次就进入新的一层。为了防止递归调用无终止地进行,必须在函数内有终止递归调 用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。下 面举例说明递归调用的执行过程。 【例 8.6】利用函数递归调用实现程序设计,求 n!。 算法设计:编写求阶乘的函数 fact; 判断 n=1 时,返回值 1; 判断 n≥2 时,函数 fact 调用 n*fact(n-1) ④ 编写主函数调用函数 fact; 调用过程如图 8.3 所示:
s=5*fac(4) 5*24 图83函数递归调用示意图 代码清单8.7: #include”stdio.h" int fact(intn) if(n=1) return 1; else retumn n*fact(n-1) int s; s=fact(5): printf"s=%dn"s) 运行结果:s=120。 8.5数组作为函数参数 数组可以作为函数的参数使用,进行数据传送。数组用作函数参数有两种形式,一种是 把数组元素(下标变量)作为实参使用:另一种是把数组名作为函数的形参和实参使用。 1.数组元素作函数实参 数组元素就是下标变量,它与普通变量并无区别。因此它作为函数实参使用与普通变量 是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值 传送。 【例8.7】判别一个数组中各元素的值,若大于零则输出该值,若小于等于零则输出0值。 代码清单8.8 include"stdio.h" void nzp(imtv) i讽v>0) printf"%d"v)
图 8.3 函数递归调用示意图 代码清单 8.7: #include "stdio.h" int fact(int n) { if(n==1) return 1; else return n*fact(n-1); } main() { int s; s=fact(5); printf("s=%d\n",s); } 运行结果:s=120。 8.5 数组作为函数参数 数组可以作为函数的参数使用,进行数据传送。数组用作函数参数有两种形式,一种是 把数组元素(下标变量)作为实参使用;另一种是把数组名作为函数的形参和实参使用。 1.数组元素作函数实参 数组元素就是下标变量,它与普通变量并无区别。因此它作为函数实参使用与普通变量 是完全相同的,在发生函数调用时,把作为实参的数组元素的值传送给形参,实现单向的值 传送。 【例 8.7】判别一个数组中各元素的值,若大于零则输出该值,若小于等于零则输出 0 值。 代码清单 8.8: #include "stdio.h" void nzp(int v) { if(v>0) printf("%d ",v); s=5*fact(4) 4*fact(3) 3*fact(2) 2*fact(1) 1 2*1 3*2 4*6 f=5*24