第七章-库函数函数的定义与返回值课件_第1页
第七章-库函数函数的定义与返回值课件_第2页
第七章-库函数函数的定义与返回值课件_第3页
第七章-库函数函数的定义与返回值课件_第4页
第七章-库函数函数的定义与返回值课件_第5页
已阅读5页,还剩55页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第七章函数在解决一个比较复杂的实际问题时,不可能把所有要完成的任务全都写在main函数中。这时,程序往往由一个main函数和若干个其它函数组成,每个函数各自完成相对独立的部分功能。在前面的章节中,我们编写的程序都是由一个main函数来组成,在main函数中调用过scanf、printf等系统函数。模块化的程序设计方法函数间相互调用的示意

main()f1()f11(){{{┇┇┇f1();f11();}┇┇

f12()f2();f12();

{┇┇

┇}}

}f2()f21(){{┇┇f21();}┇}函数的分类从函数形式无参函数有参函数

?我们学习过哪些无参函数和有参函数?从用户角度标准函数(库函数):由系统提供用户自定义函数库函数由系统提供,用户只要按照要求的格式正确调用即可。不同的C编译系统提供的库函数有些不同。

§7.1

库函数使用库函数应注意的问题:1、调用库函数时要用#include命令将相关的头文件包含进来。如:调用数学函数,用#include"math.h"

|<math.h>

调用输入输出函数,用#include"stdio.h"

|<stdio.h>

调用字符函数,用#include"

ctype.h"

|<ctype.h>

2、库函数调用的一般形式:

函数名(参数表)

要注意函数的功能、参数的个数与类型、函数值的类型。如:求平方根的函数sqrt的形式是:doublesqrt(doublex)3、库函数调用以两种方式出现。其一:出现在表达式中,即作为表达式的一部分参与运算。如:计算y=x2.5+1.3,则通过以下语句调用来实现。

y=pow(x,2.5)+1.3;其二:独立的语句,即调用函数后加一分号。 如:printf("*****\n");4、调用库函数时,要注意参数的一些特殊要求。如三角函数要求自变量参数用弧度表示,开平方函数要求自变量参数的值大于或等于0。使用库函数应注意的问题(续)函数返回值的类型缺省int型无返回值:void函数体函数类型函数名(形参类型说明表)

{

说明部分执行部分

}§7.2

函数的定义和返回值1.函数定义的一般格式现代风格:多个形参说明之间要用逗号隔开没有形参时,这一对括号不能省略合法标识符如果函数的类型不是void,函数体最后要用return语句去返回一个值.例1有参函数(现代风格)

intmax(intx,inty){intz;z=x>y?x:y;return(z);}例2有参函数(现代风格)

intmax(intx,y){intz;z=x>y?x:y;return(z);}例3无参函数

voidprintstar(){printf("**********\n");}或

voidprintstar(void){printf("**********\n");}函数的定义示例例4空函数

voiddummy(void){

}函数体为空(留待以后补充)

intmax2(intx,inty)/*现代风格*/{intmax;if(x>y)max=x;elsemax=y;printf("max(max2)=%d\n",max);return(max);}voidmain(){inta,b,max;scanf("%d,%d",&a,&b);

max=max2(a,b)+100;printf("max(main)=%d\n",max);}例函数的定义

形参和函数体中定义的变量只在函数被调用时才临时分配存储单元,当退出函数时,这些存储单元全部被释放(称为局部性,因而与其它函数中的变量同名不会引起混淆)。

main()时,main函数是什么类型的?可改写为max=x>y?x:y;形参实参函数与函数之间是平等的voidmain(){intmax2(intx,inty){intz;if(x>y)z=x;elsez=y;return(z);}inta,b,max;scanf("%d,%d",&a,&b);max=max2(a,b);printf("max=%d\n",max);}

函数的定义是平行的,不能在一个函数的内部再定义其它函数。即每个函数都是一个相对独立的模块,不能在写某一个函数时又包含了另一个函数的定义(main函数的执行时有一点点小的特权!)。

返回语句形式return(表达式);或

return表达式;

return;功能:使程序控制从被调用函数返回到调用函数中,同时把返值带给调用函数说明:函数中可以有多个return语句,但只有其中的一个return语句能够得到执行若函数中没有return语句,或者是一个不带表达式的return语句,则该函数结束时自动返回调用函数一个不确定的值若函数类型与return语句中表达式值的类型不一致,按前者为准,自动转换------函数调用转换void型函数:明确说明函数没有返回值2.函数的返回值intmax(floatx,floaty){floatz;z=x>y?x:y;

return(z);}main(){floata,b;scanf("%f,%f",&a,&b);printf("Maxis%d\n",max(a,b));}例函数返回值类型转换

main(){inta,b,max;scanf("%d,%d",&a,&b);max=max2(a,b);printf("max=%d\n",max);}intmax2(intx,inty){intz;if(x>y)

returnx;else

returny;}例函数可以有多个return语句注意:在C语言中,函数名不能被赋值,只能通过return语句返回一个值。

intmax2(intx,inty){max2=x>y?x:y;}

printstar(){printf("*********\n");}main(){inta;a=printstar();printf("a=%d\n",a);}输出:a=10例函数带回不确定值printstar()是什么类型?void型函数:明确说明函数没有返回值#include<stdio.h>/*void*/printstar(){printf("*****@@@##****\n");}main(){inta;a=printstar(); a=printstar();printf("a=%d\n",a);}voidprintstar(){printf("*********\n");}main(){inta;a=printstar();printf("a=%d",a);}编译错误!(VC++)errorC2120:'void'illegalwithalltypes说明:(1)调用函数时,其名字必须与定义的名字相同。

(2)函数调用时的实参只写名字不需要在名字前再带实参类型。

如上面main函数中对max2函数的调用不能写成:max=max2(inta,intb);

§

7.3函数的调用

1.函数调用的一般形式:函数名(实参表);说明:

(3)实参与形参,个数应一致。若实参少,则必有形参未得到值(不确定值),影响结果。若实参多,则多余的无效(TC)。如:c=max2(3);则c的值为:761(随机值)

若:c=max2(3,5,8);则c的值为:5(4)实参与形参的类型应一一对应相匹配。若不匹配,程序仍能运行,但得不出正确结果(TC)。如:c=max(3.0,5.0);则c的值为:0

若:c=max(3L,5L);则c的值为:3函数调用说明(续)(5)函数必须先定义,后调用。将要被调用的函数定义在前,调用在后。返回值类型为int或char的函数可例外。(6)函数可直接或间接地自己调用自己(递归调用,在7.6节介绍)函数调用说明(续)(7)实参表求值顺序,因系统而定(TurboC自右向左)#include"stdio.h"voidmain(){intp=2;printf("%d,%d,%d\n",p,++p,p);}/*TC:3,3,2VC:3,3,2*/#include"stdio.h"voidmain(){intp=2;printf("%d,%d,%d\n",p,p++,p);}/*TC:3,2,2VC:2,2,2*/P192.函数调用的方式1.函数表达式:例m=max(a,b)*2;2.函数语句:

例printstar();printf("Hello,World!\n");3.函数参数:例printf("%d",max(a,b));m=max(a,max(b,c));§

7.4函数的说明

在C语言中,除了主函数外,对于用户定义的函数要遵循“先定义,后使用”的规则。凡是未在调用之前定义的函数,C编译程序默认函数的返回值为int类型。对于返回值为其它类型的函数,若把函数的定义放在调用之后,应该在调用之前对函数进行说明(或称为函数原型说明)。C语言对被调用函数要求:必须是已存在的函数库函数:#include<*.h>用户自定义函数:函数类型说明1.函数说明一般形式

函数类型函数名(形参类型[形参名],…..);

函数类型函数名();或main(){floata,b,c;

floatmax2(floatx,floaty);/*函数的说明*/scanf("%f%f",&a,&b); c=max2(a,b);

/*函数的调用*/

printf("%f\n",c);}floatmax2(floatx,floaty)/*以下为函数的定义*/{floatz;if(x>y)z=x; else z=y;return(y);}例如:函数说明语句作用:告诉编译系统max2函数是float类型的、有2个float类型的参数。可选在VC中不允许说明

(1)函数说明可以是一个独立的语句;如上面例子中就是采用独立语句的形式。

(2)函数说明中的形参名是一种虚设,它们可以是任意的用户标识符,既不必与函数首部中的形参名一致,又可以与程序中的任意用户标识符同名。因此,参数名也可以省略。如上面的例子中函数说明可写成:floatmax2(float,float);

(3)注意函数定义与函数说明是不同的,定义是写出函数的完整形式,而说明是告诉系统此函数的返回值类型、参数的个数与类型,便于编译时进行有效的类型检查。

(4)若函数的返回值类型为int或char,则可以不进行函数说明(系统默认)。但是使用这种方法时,系统无法对参数的类型做检查。若调用函数时参数使用不当,在编译时也不会报错。因此,为了程序清晰和安全,建议都进行说明为好。

(5)若被调函数的定义出现在主调函数之前,也可以不进行函数说明。

(6)有些系统(如BorlandC++、VC++等)要求一定要用函数说明指出函数类型和形参类型,并且对void和int型函数也要进行函数说明。main(){inta,b,c;

scanf(“%f%f”,&a,&b); c=max2(a,b);

/*函数的调用*/

printf(“%f\n”,c);}intmax2(intx,inty)/*以下为函数的定义*/{intz;if(x>y)z=x; else z=y;return(z);/*书错为return(y)*/}int型函数可不作函数说明(BorlandC++不行)floatmax2(floatx,floaty)/*以下为函数的定义*/{floatz;if(x>y)z=x; else z=y;return(z);/*书错为return(y)*/}main(){floata,b,c;

scanf(“%f%f”,&a,&b); c=max2(a,b);

/*函数的调用*/

printf(“%f\n”,c);}被调函数出现在主调函数之前,不必函数说明main(){floatadd(float,float);/*functiondeclaration*/floata,b,c;scanf("%f,%f",&a,&b);c=add(a,b);printf("sumis%f",c);}floatadd(floatx,floaty){floatz;z=x+y;return(z);}也可写成:floatadd();例函数说明举例2.函数说明的位置

(1)放在调用函数的说明部分(只有此调用函数能识别被调用函数)。可以是独立语句,也可与其它变量的定义放在同一个语句中。如上面的用法也可以如下形式的语句:floata,b,c,max2(float,float);(2)放在所有函数的外部,被调用之前。(此时函数说明的后面所有位置上都可对该函数进行调用)。floatmax2(float,float);main(){floata,b,c;scanf(“%f%f”,&a,&b);c=max2(a,b);printf(“%f”,c);}floatmax2(floatx,floaty){……}函数说明放在所有函数的外部例函数说明举例

(3)调用库函数时,要在程序的开头使用命令:#include<*.h>

来包含相关的头文件,就是因为头文件中包含了这些库函数的原型说明。

形参与实参的概念形式参数:定义函数时函数名后面括号中的变量名实际参数:调用函数时函数名后面括号中的表达式§7.5

调用函数和被调用函数之间的数据传递

intmax2(intx,inty){intz;z=(x>y)?x,y;return(z);}main(){inta,b,c;

a=30,b=58; c=max2(a,b);c=max2(a+5,100);printf(“%f\n”,c);}例如:形参:x,y形参必须指定类型;实参:a,b实参:

a+5,100(1)实参表达式也可以是变量或常量,但必须有确定的值;(2)要求形参与实参类型一致,个数相同(多:略/少:随机值);(4)形参在函数被调用前不占内存;函数调用时为形参分配内存;调用结束,内存释放;(5)C语言的参数传递方式

值传递方式:函数调用时,系统临时为被调函数的形参分配存贮单元,并将实参的值复制到形参中;当被调函数结束时,形参单元被释放,实参单元仍保留并维持原值。特点:单向的值传递(数值或地址值)。有关参数传递的几点说明xaproduct××××1.21.21.7281.变量作为参数(单向的数值传递)#include<stdio.h>floatcube(floatx){return(x*x*x);}voidmain(){floata,product;printf("Pleaseinputvalueofa:");scanf("%f",&a);product=cube(a);printf(”Cubeof%.4fis%.4f\n",a,product);}例计算x的立方Cube[kju:b]n.立方体,立方main(){voidswap(int,int);intx=10,y=20;printf(“(1)x=%dy=%d\n”,x,y);swap(x,y);printf(“(4)x=%dy=%d\n”,x,y);}voidswap(inta,intb){intt;printf(“(2)a=%db=%d\n”,a,b);t=a;a=b;b=t;printf(“(3)a=%db=%d\n”,a,b);}例7.1

函数参数之间的单向传递1020x:y:调用前:调用结束:1020x:y:调用:1020a:b:1020x:y:swap:1020x:y:2010a:b:t:程序运行结果为:(1)x=10y=20(2)a=10b=20(3)a=20b=10(4)x=10y=20main(){voidex(intz,inty,intx);intx=10,y=20,z=30;printf(“(1)x=%dy=%dz=%d\n”,x,y,z);ex(y,z,x);}voidex(intx,inty,intz){printf(“(2)x=%dy=%dz=%d\n”,x,y,z);}例7.2实参向形参按位置传递数据程序运行结果为:(1)x=10y=20z=30(2)x=20y=30z=10实参:3010y:z:3010z:x:形参:20x:20y:函数说明语句形参名是一种虚设函数调用语句确定实参顺序函数定义确定形参顺序实参向形参按位置传递数据#include<stdio.h>

longsum(inta,intb);longfactorial(intn);voidmain(){intn1,n2;longa;scanf("%d,%d",&n1,&n2);a=sum(n1,n2);printf("a=%1d",a);}longsum(inta,intb){longc1,c2;c1=factorial(a);c2=factorial(b);

return(c1+c2);}

longfactorial(intn){longrtn=1;inti;for(i=1;i<=n;i++)rtn*=i;

return(rtn);}文件包含编译预处理命令函数说明函数调用函数调用函数返回值补充例题longsum(inta,intb);longfactorial(intn);形参实参函数定义

当数组名作为函数参数时,要求实参和形参都用数组名(或指针变量,第十章作介绍)。由于数组名的值就是数组在内存中分配的存储空间的首地址,这种方法称之为“传址调用”方式。当把实参数组名的值(首地址)传给形参数组名后,由于形参数组名也代表首地址,这样实参数组和形参数组的首地址相同,即实参数组和形参数组占用相同的存储空间。在被调函数中,形参数组中各元素的值如果发生变化,就会使实参数组元素的值同时也发生变化。在函数调用结束后,虽然形参数组已不复存在,但实参数组元素的值已发生变化,可以在主调函数中进行使用。2.数组名作为参数

(单向的地址值传递)例7.3选择法排序对N个数排序的算法步骤如下:

(1)在N个数中寻找最小值,然后把这个最小值与最前面的那个数交换位置。i=0;/*最前面的那个数下标*/k=i;/*k为当前最小值的下标*/for(j=i+1;j<N;j++)if(a[j]<a[k])k=j;t=a[k];a[k]=a[i];a[i]=t;

程序为:

(2)排除最前面的那个数(i=i+1),在余下的N-1个数中寻找最小值,然后把这个最小值与最前面的那个数交换位置。

……如此循环,直到最后只剩一个数(i=N-1)时结束。对10个数排序的算法步骤演示如下:28478352738615668下标:0123456789第一步:i=0,k=5:a[0]a[5]24783528738615668第二步:i=1,k=1:a[1]a[1]?24783528738615668第三步:i=2,k=6:a[2]a[6]24788287335615668第四步:i=3,k=5:a[3]a[5]22888477335615668第五步:i=4,k=6:a[4]a[6]22888473573615668第六步:i=5,k=5:不交换!第七步:i=6,k=7:a[6]a[7]22888473556617368对10个数排序的算法步骤演示如下:28478352738615668下标:0123456789第七步:i=6,k=7:a[6]a[7]22888473556617368总结:10个数排序,需要进行九次的上述操作。若有N个数需要排序,则需要进行N-1次的上述操作。第九步:i=8,k=9:a[8]a[9]22888473556686173第八步:i=7,k=8:a[7]a[8]2288847355673616810个数排序的完整程序如下:voidsort(inta[10]){inti,j,k,t;for(i=0;i<9;i++)

{k=i;for(j=i+1;j<10;j++)if(a[j]<a[k])

k=j;t=a[k];a[k]=a[i];a[i]=t;

}}main(){inti,x[10]={5,7,4,2,8,6,1,9,0,3};printf("theoriginalarray:\n");for(i=0;i<10;i++)printf("%d",a[i]);printf("\n");

sort(x);printf("thesortedarray:\n");for(i=0;i<10;i++)printf("%d",a[i]);printf("\n");}程序运行结果为:theoriginalarray:5742861903thesortedarray:0123456789voidsort(inta[],intn)for(i=0;i<n-1;i++)sort(x,10);N个数排序的完整程序如下:n例7.4将一个数组中的n个数据按颠倒的顺序重新存放解题思路为:借助于一个临时变量,将a[0]与a[n-1]对换,再将a[1]与a[n-2]对换,……,直到将a[(n-1)/2-1]与a[n-int((n-1)/2)-1]对换。程序采用循环来实现,设二个“位置指针变量”i和j,i的初值为0,j的初值为n-1,将a[i]与a[j]交换,然后使i的值加1,j的值减1,再将a[i]与a[j]交换,直到i=m为止。m=(n-1)/2为“中间位置”。见图7.2所示。102030405060708090100i=0j=n-1100203040506070809010i=1j=n-2m=(n-1)/2数组逆序程序voidinv(intx[],intn){intt,i,j,m=(n-1)/2;for(i=0;i<=m;i++){j=n-1-i;t=x[i];x[i]=x[j];x[j]=t;}}main(){inti,a[10]={10,20,~,90,100};printf("Theoriginalarray:\n");for(i=0;i<10;i++)printf("%d",a[i]);printf("\n");

inv(a,10);printf("Thearrayhasbeeninverted:\n");for(i=0;i<10;i++)printf("%d",a[i]);printf("\n");}程序运行结果为:Theoriginalarray:102030405060708090100Thearrayhasbeeninverted:100908070605040302010voidinv(intx[],intn){intt,i,j=n-1;for(i=0;i<j;i++,j--){t=x[i];x[i]=x[j];x[j]=t;}}例7.5求二维数组每行元素的平均值

voidlineave(intx[][4],floaty[],intn){inti,j,s;for(i=0;i<n;i++){s=0;for(j=0;j<4;j++)s=s+x[i][j];

y[i]=s/4.0;/*书印错:b[i]=s/4.0*/}}main(){inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};inti,j;floatb[3];lineave(a,b,3);for(i=0;i<3;i++){for(j=0;j<4;j++)printf(“%4d”,a[i][j]);printf(“ave:%6.2d\n”,b[i]);}}程序运行结果为:

1234ave:2.505678ave:6.509101112ave:10.50main()调用函数a结束a函数b函数调用函数b1.嵌套调用C规定:函数定义不可嵌套,但可以嵌套调用函数7.6

函数的嵌套与递归调用#include<stdio.h>

intdif(intx,inty,intz);intmax(intx,inty,intz);intmin(intx,inty,intz);voidmain(){inta,b,c,d;scanf("%d%d%d",&a,&b,&c);

d=dif(a,b,c);printf("Max-Min=%d\n",d);}intdif(intx,inty,intz){returnmax(x,y,z)-min(x,y,z);}intmax(intx,inty,intz){intr;r=x>y?x:y;return(r>z?r:z);}intmin(intx,inty,intz){intr;r=x<y?x:y;return(r<z?r:z);}main()调用函数dif输出结束dif函数max函数调用函数max调用函数minmin函数例求三个数中最大数和最小数的差值例用弦截法求方程根xyf(x)0x1x2xf(x1)f(x2)求两点连线与x轴的交点x输入x1,x2,求f(x1),f(x2)直到f(x1)与f(x2)异号y=f(x),y1=f(x1)y与y1同号真假x1=xy1=yx2=x直到

|y|<root=x输出

rootroot函数运行情况:Inputx1,x2:2,6Arootofequationis5.0000main()调用函数root输出根x结束root函数xpoint函数调用函数xpoint调用函数ff函数函数的嵌套举例2.递归调用定义:函数直接或间接的调用自身叫函数的递归调用f()调f调f2调f1f1()f2()说明C编译系统对递归函数的自调用次数没有限制每调用函数一次,在内存堆栈区分配空间,用于存放函数变量、返回值等信息,所以递归次数过多,可能引起堆栈溢出intf(intx){inty,z;……

z=f(y);…….return(2*z);}intf1(intx){inty,z;……

z=f2(y);…….return(2*z);}intf2(intt){inta,c;……

c=f1(a);…….return(3+c);}#include<stdio.h>intfac(intn){intf;if(n==0||n==1)f=1;elsef=fac(n-1)*n;return(f);}main(){intn,y;printf("Inputaintegernumber:");scanf("%d",&n);

y=fac(n);printf("%d!=%15d",n,y);}intfac(intn)/*更完善的阶乘函数*/{intf;

if(n<0){printf("n<0,dataerror!");return(-1);}if(n==0||n==1)f=1;elsef=fac(n-1)*n;return(f);}递归方法的要点:1.

递推公式

fn=fn-1*n2.

结束条件。

n==0||n==1例7.6用递归的方法求n的阶乘#include<stdio.h>intfib(intn){intf;if(n==1||n==2)f=1;elsef=fib(n-2)+fib(n-1);return(f);}main(){intn,s;printf("Inputaintegernumber:");scanf("%d",&n);

s=fib(n);printf("fib(%d)=%15d",n,y);}递归方法的要点:1.

递推公式

fn=fn-2+fn-12.

结束条件。

n==1||n==2例7.7用递归实现斐波那契数列

#include"math.h"intisprime(int);main(){intx;scanf("%d",&x);if(isprime(x))printf("%disprime\n",x);elseprintf("%disnotprime\n",x);}isprime(intn){inti;for(i=2;i<=sqrt(n);i++)if(n%i==0) return0;return1;}编写函数isprime(intn)用来判断自变量n是否为素数,若是,函数返回1,否则返回0。isprime(intn){inti,flag=1;for(i=2;i<=sqrt(n);i++)if(n%i==0){flag=0;break;}return(flag);}isprime(intn){inti,flag=1;for(i=2;i<=sqrt(n)&&

flag==1;i++)if(n%i==0)flag=0;return(flag);}7.7

函数程序举例例7.8

#include"math.h"intisprime(int);

voideven(int);main(){inta;printf("Enteraevennumber:");scanf("%d",&a);if(a%2==0)even(a);elseprintf("The%disn’tevennumber\n",a);}voideven(intx){inti;

for(i=2;i<=x/2;i++)if(isprime(i))if(isprime(x-i)) {printf("%d=%d+%d\n",x,i,x-i);return;}}isprime(intn){……}例7.9

编写函数,验证任意偶数为两个素数之和并输出这两个素数。

程序运行结果为:Enteraevennumber:10<CR>10=3+7break;例7.10利用梯形法求定积分

xy0

a

b

f(a)f(b)a+hf(a+h)hh利用梯形法求定积分doubleinteg(doublea,doubleb){doubles,x,h,f(double);intn=100,i;h=fabs(b-a)/n;s=(f(a)+f(b))/2.0;for(i=1;i<=n-1;i++){x=a+

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论