分校课件第讲函数_第1页
分校课件第讲函数_第2页
分校课件第讲函数_第3页
分校课件第讲函数_第4页
分校课件第讲函数_第5页
已阅读5页,还剩32页未读 继续免费阅读

下载本文档

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

文档简介

分校课件第讲函数第一页,共四十八页,编辑于2023年,星期五简介分而治之与程序的模块化C语言的基本思想,就是将一个规模较大的问题分解成若干较小的相对独立的部分来解决,前一章介绍采用结构化程序设计。本章介绍函数,它可以把一个规模较大的问题分解成若干个较小的相对独立的部分,对每一个部分使用一个较小的程序段,即程序模块(module)来处理。而且可以反复调用。从较小的程序段或组件来构建程序。这些小片段或组件比原始程序更容易实现和管理。这些小组件可以被重复使用。被本程序和其他程序使用。函数第二页,共四十八页,编辑于2023年,星期五C语言的函数在C语言中,函数(function)是构成程序的基本模块。一个C程序由一个或多个函数组成,有且仅有一个主函数,即main()函数。每个函数完成一个相对独立且功能明确的任务。由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次。函数mainfun_afun_bfun_cfun_cfun_dfun_efun_ffun_d第三页,共四十八页,编辑于2023年,星期五二.用户自定义函数1.函数分类(从函数的形式看)无参函数有参函数◆函数定义时无参数说明◆调用无参函数一般用来执行指定的一组操作◆主调函数不传送数据给被调函数●函数定义时定义了一个或一个以上的参数●调用时将要处理的数据传送给被调函数空函数◆定义时既无参数也无执行语句◆被调用时,不执行任何操作就立即返回6.2函数的定义第四页,共四十八页,编辑于2023年,星期五C语言的函数C语言的函数有两大类:标准库函数编译系统提供了丰富的函数。例如数学计算:sqrt(),abs()输入/输出:scanf(),printf()自定义函数程序员自己可以编写函数来完成特定的任务。应该熟悉C系统中的标准函数库。应该避免从零开始构建一切。注意使用时要按规定的格式进行使用。函数第五页,共四十八页,编辑于2023年,星期五为什么使用函数函数使程序模块化。程序采用模块化结构的好处:分而治之提高程序开发的效率。改进性能。使程序易于管理和集中控制。代码重用使用现有的函数作为构件来创建程序。函数可以被重复使用。避免重复代码段降低了复杂性。抽象隐藏了实现的细节(数据结构,顺序、指针,全局变量)。进行参数传递。函数我们使用库函数(printf()),并不知道它的具体实现方法,却并不影响对他的使用。例如第六页,共四十八页,编辑于2023年,星期五案例分析:一个简单的函数编写和使用一个简单的函数(cw0801.c)定义一个函数square,用来计算任意整数的平方。然后,使用该函数计算从1到10所有整数的平方。函数#include<stdio.h>intsquare(int);intmain(){

intx;for(x=1;x<=10;x++)printf("%d",square(x));

return0;}intsquare(inty)//定义平方函数{

returny*y;}声明函数使用函数149162536496481100如果函数在主调函数之后定义,则使用前必须先声明函数原形。第七页,共四十八页,编辑于2023年,星期五函数的定义定义函数的格式<函数类型><函数名>(<参数表>){<函数体语句>}函数名:一个有效的标识符。函数类型:返回值的类型说明符。如果不指定,即缺省,就是int。最好不省略。C99不允许省。void:表示函数不返回任何值。不可省。参数表:声明参数,多个参数用逗号分隔。接收传递进来的数据。必须为每个参数指定数据类型。int可以省略。但最好不要省略。函数函数头函数体Void能用在:1、对函数返回的限定;2、对函数参数的限定。3、指针的限定第八页,共四十八页,编辑于2023年,星期五函数的定义函数体:包括声明语句和可执行语句。在函数体内可以定义变量。不能定义函数,即函数的定义不允许嵌套。控制返回:结束执行,把程序的控制交还主调函数,也可以用return返回一个数值。}return;return<表达式>;如:return(x>y?x:y);函数无返回值,只返回控制权有返回值如果函数无参数,那么应声明其参数为void:Intfunction(void){

return1;}第九页,共四十八页,编辑于2023年,星期五案例分析:函数的定义函数的定义(cw0802.c)定义函数找出三个数中的大数。函数#include<stdio.h>intmaximum(intx,inty,intz);intmain(){

inta,b,c;printf(“inputthreeintegers:");scanf("%d%d%d",&a,&b,&c);printf(“Maximumis:%d\n”,maximum(a,b,c));

return0;}intmaximum(intx,inty,intz){

intmax=x;

if(y>max)max=y;

if(z>max)max=z;

returnmax;}maximumintintintint函数原型接口(interface)声明函数原形必须加;return(max)括号可省return(x>y?x:y);第十页,共四十八页,编辑于2023年,星期五函数原型函数原型

<函数类型><函数名>(<参数表>);用来对函数进行声明。编译器使用函数原型来检查函数调用的合法性。注意:函数原型要与函数的定义一致。例如

intmaximum(inta,intb,intc); intmaximum(int,int,int);函数在使用自定义函数时,除了进行定义之外,还要对被调用函数进行说明,说明函数类型、名称和参数类型,这称为函数原形。如果被调用函数在调用函数之后定义,则必须先声明原形.第十一页,共四十八页,编辑于2023年,星期五函数原型函数原型在程序文件中的位置不同,作用范围不同在所有函数的外面在调用函数内部函数main(){…}voidfuncA(){

intfuncB(int);…}intfuncB(int){…}函数原形在函数外声明,其作用范围从声明处开始,至程序结束。在函数中声明,只能在函数中起作用。第十二页,共四十八页,编辑于2023年,星期五函数原型如果程序中没有包含函数原型。编译程序会使用该函数第一次出现的情形来形成自己的函数原型。函数的定义在前函数的调用在后默认情况下,编译程序假定函数返回int型的结果,但不会对参数进行任何假定。如果传递给函数的参数不正确,编译程序不会检查到这些错误。函数不要省略返回值的类型,如果函数没有返回值,那么应声明为void类型。第十三页,共四十八页,编辑于2023年,星期五函数原型函数原型强迫参数采用正确的数据类型。举例printf(“%.3f”,sqrt(4));函数原型使编译程序把整数值4转换为double型的值4.0没有与函数原型中的参数类型完全对应的参数值会在调用函数之前被转换成合适的数据类型。遵守C语言的提升规则。函数doublesqrt(double);第十四页,共四十八页,编辑于2023年,星期五函数原型与头文件头文件每个标准库函数都有对应的头文件。包含了标准库中所有函数的函数原型,以及那些函数所需的数据类型和常量的定义。使用#include命令把头文件包含到程序文件中:#include<文件名>例如,#include<math.h>程序员可以创建自己的头文件使用.h扩展名。使用下面的命令格式包含头文件:#include“文件名”例如,#include“abc.h”函数尖括号指只在include文件夹下查找引号指先在本程序所在文件夹查找,再在include文件夹下查找第十五页,共四十八页,编辑于2023年,星期五形参形参函数intmax(int

a,int

b){

intc=a>=b?a:b;

returnc;}intmain(){

inta,b,c;scanf(“%d%d”,&a,&b);c=max(a,b);

return0;}实参实参形式参数简称“形参”。在定义被调函数时定义,表示可以接受传递过来的值。只能是变量形式。只有在函数被调用、启动后,才临时为其分配存储单元,并接受主调函数传来的数据。在函数调用结束后,形参所占存储单元被释放,即值不保留。实际参数:简称“实参”。在函数调用时给出。实参是函数调用时主调函数传送给被调函数形参的实际值。实参可以是常量、变量和表达式但实参必须有确定的值。如有多个形参或者多个实参,参数之间用逗号分隔。不能用其他符号。第十六页,共四十八页,编辑于2023年,星期五参数传递参数传递的顺序。函数intmax(inta,intb){

intc=a>=b?a:b;printf("%d,%d,%d\n",c,a,b);

returnc;}intmain(){

intx=6,y;y=max(x,x++);printf(“x=%d,y=%d\n",x,y);

return0;}当实参表列中有多个实参时,对实参的求值顺序,C语言未规定。VC和BC是按从右往左的顺序求值。b=x++;a=x;6,6,6X=7,y=6在参数传递时x=6,传递完成后才加1b=++x;a=x;7,7,7X=7,y=7cw0802_x.c如改为在参数传递时x=7,传递的a,b都为7第十七页,共四十八页,编辑于2023年,星期五参数传递参数传递的影响。函数intmax(inta,intb){

intc=a>=b?a:b;

a++;b++;

printf("%d,%d,%d\n",a,b,c);

returnc;}intmain(){

inta=6,b=5,c;c=max(a,b);printf(“%d,%d,%d”,a,b,c);

return0;}实参与形参不共用存储单元。参数传递时,把实参的值复制一份给形参。形参值的变化不影响实参的值。所以,形参和实参可以同名。max6a5b7a6bmaincw0802_y.c而返回值总是67,6,66,5,6主函数main中函数max中第十八页,共四十八页,编辑于2023年,星期五值传递和引用传递函数间参数的传递有两种类型:值传递主调函数把实参的值的副本传递给被调函数的形参。在被调函数内改变形参的值不会改变主调函数中实参的值。如果函数不需要修改参数的值,就采用这种调用方式。引用传递主调函数把实参“自身”传递给被调函数的形参。在被调函数内改变形参的值将改变主调函数中实参的值。用于可信的函数。函数但C语言的数组名作为参数传递时,则是传址,此时在被调函数内形参变化将影响实参值。这将在数组章中讲授。在指针一章中讲指针传递。第十九页,共四十八页,编辑于2023年,星期五参数传递实参和形参的类型应该相同或赋值兼容。(cw0803.c)定义函数找出二个数(字符)中的大数。函数intmax(int

a,int

b){

intc=a>=b?a:b;returnc;}intmain(){

intx=6,y=5,z;z=max(x,y);printf(“%d”,z);

return0;}如果x,y是整型,则结果正确;如果x,y是字符型,则自动进行类型转换,结果正确;如果x,y是短整型,则自动进行类型转换,结果正确;如果x或y是实数,则自动进行类型转换,有数据丢失,结果可能不正确。b=y;a=x;即b=5a=6在参数传递时第二十页,共四十八页,编辑于2023年,星期五函数的返回值函数返回值的类型应该与函数的类型一致。如果不一致,采用函数的类型,对返回值进行类型转换。函数#include<stdio.h>intmax(floata,floatb){

floatc=a>=b?a:b;

printf("c=%f\n",c);

returnc;}intmain(){

floatx=6.5,y=5.6,z;z=2*max(x,y);printf(“z=%f”,z);

return0;}c的类型?返回值的类型?max(x,y)的类型?Z=2*max(x,y)的类型?(cw0803-x.c)注意:被调用函数如果在主函数的后面,则结果不正确,因为未说明函数原形,必须加一语句函数原形声明:intmax(floata,floatb);C=6.500000Z=12.00000第二十一页,共四十八页,编辑于2023年,星期五函数的嵌套调用嵌套调用在调用一个函数的过程中又调用另一个函数函数主函数调用函数1函数1调用函数2函数2123456789第二十二页,共四十八页,编辑于2023年,星期五案例分析:函数的嵌套调用计算圆环的面积分析圆环的面积=外圆的面积–内圆的面积可以定义两个函数circleArea计算圆的面积ringArea计算圆环的面积函数r1r2circleAreadoubledoubleringAreadoubledoubledoubledoublecircleArea(doubler);doubleringArea(doubler1,doubler2);第二十三页,共四十八页,编辑于2023年,星期五案例分析:函数的嵌套调用计算圆环的面积源代码(cw0804.c)函数#include<stdio.h>#definePI3.14doublecircleArea(doubler);doubleringArea(doubler1,doubler2);intmain(){

doubler1,r2,s;printf("\tinputr1,r2:");scanf("%lf%lf",&r1,&r2);s=ringArea(r1,r2);printf("\n\tTheareais:%.2lf\n",s);

return0;}第二十四页,共四十八页,编辑于2023年,星期五案例分析:函数的嵌套调用计算圆环的面积源代码(续)函数double

circleArea(doubler){returnPI*r*r;}double

ringArea(doubler1,doubler2){

if(r1<=r2)returncircleArea(r2)-circleArea(r1);

elsereturncircleArea(r1)-circleArea(r2);}Inputr1,r2:12Theareais:9.42被调函数中可用多个return语句。第二十五页,共四十八页,编辑于2023年,星期五递归函数递归函数直接或间接调用自己的函数。函数函数1调用函数1函数1调用函数2函数2调用函数1第二十六页,共四十八页,编辑于2023年,星期五案例分析:递归函数用递归方法计算n!。分析5!=5*4*3*2*15!=5*4!4!=4*3!...递归公式函数n!=1(n=0或1)n*(n-1)!

(n>1)基本情形简化问题s=1;n=1;while(n<=20)

s=n*s;迭代n!

=n*

(n-1)!

第二十七页,共四十八页,编辑于2023年,星期五案例分析:递归函数举例:用递归方法计算n!。函数/*用递归方法计算n!(cw0805.c)*/#include<stdio.h>long

fac(intn){longs;//声明长整变量f

if(n==0||n==1)

s=1;

elses=n*fac(n-1);//反复自调用fac并输出

printf("\t%d!=%ld\n",n,s);

returns;}intmain(){printf("\n\t5!=%ld\n",fac(5));

return0;}1!=12!=23!=64!=245!=1205!=120递归调用源代码(cw0805.c)第二十八页,共四十八页,编辑于2023年,星期五案例分析:递归函数举例:用递归方法计算n!。分析函数5!5*4!4*3!3*2!2*1!11205*244*63*22*11递归调用从递归调用返回值第二十九页,共四十八页,编辑于2023年,星期五//求1!+2!+3!+4!+….+20!#include<stdio.h>floatsum(int);floatfac(int);intmain(){ floatsum(int);

floatadd; add=sum(20); printf("add=%e",add);

return0;}floatsum(intn){floatfac(int);

inti;

floats=0;for(i=1;i<=n;i++) s+=fac(i);

returns;}floatfac(inti){floatt=1;

intn=1;

do{ t=t*n; n++;}

while(n<=i);

returnt;}//运行结果为:s=2.56133e+18,可能最后一位不准确。(cw0806.c)第三十页,共四十八页,编辑于2023年,星期五用递归方案解决问题小结用递归(函数)方案解决问题递归函数只知道如何去解最简单的情形(基本情形)简单的返回一个值把复杂的问题分成两部分:函数知道如何去做的部分函数不知道如何去做的部分这一部分与原问题相似,且更简单函数可以调用自己的新形式来解决这个更小的问题(递归调用)最终遇到基本情形函数识别出基本情形,将结果返回给前一个情形一系列的结果按顺序返回直到把最终结果返回给原始的调用者(可能是main()函数)函数第三十一页,共四十八页,编辑于2023年,星期五案例分析:递归方案使用递归方法计算斐波拉契(Fibonacci)数列。

0112358…分析从第三个数开始,每个数是前两个数的和。第一、二个数是确定的。递归公式fib(n)=fib(n-1)+fib(n-2)(当n>1时)fib(0)=0fib(1)=1函数写成递归函数有:intfib(intn){

if(n==0)return0;

if(n==1)return1;

if(n>1)returnfib(n-1)+fib(n-2);}注意编程时计项数是从第0项开始计数,第4、5、6……项为3、5、8……#include<stdio.h>intmain(void){

intn;printf("inpitn=?");scanf("%d",&n);//for(n=0;n<9;n++)printf("第%d项为%d\n",n,fib(n));return0;}(cw0807fib.c)第三十二页,共四十八页,编辑于2023年,星期五#include<stdio.h>#include

<math.h>intmain(){

floata,x1,x2;scanf("%f",&a);x1=1;x2=a;

while(fabs(x1-x2)>=1e-5){x1=x2;x2=(x1+a/x1)/2;}printf("%f,%f",x1,x2);

return0;}/*求平方根的迭代公式为Xn+1=1/2(Xn+a/Xn);要求前后两次求出的x的差的绝对值小于1e-5;*/用迭代法求a的平方根利用迭代算法解决问题,需要做好以下三个方面的工作:一、确定迭代变量。至少存在一个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。二、建立迭代关系式。如何从变量的前一个值推出其下一个值的公式(或关系)。这是建立迭代问题的关键,通常可以使用递推或倒推的方法来完成。三、对迭代过程进行控制。在什么时候结束迭代过程?(cw0806x.c)x1=1,a, (1+a)/2,Sqrt(5)=2.236067977x2=a,(1+a)/2,((1+a)/2+a/(1+a)/2)/2, 1,5, 3,2.3333, 2.23815,3, (3+5/3)/2=2.3333,(2.3333+5/2.3333)/2=2.2381, (2.2381+5/2.2381)/2=2.23606889第三十三页,共四十八页,编辑于2023年,星期五递归与迭代递归与迭代的比较循环迭代:明确使用了循环结构递归:重复调用递归函数终止条件迭代:循环条件不满足递归:遇到基本情形都有可能出现无限循环如何选择迭代:性能好递归:可读性好函数迭代递归迭代和递归各基于一种控制结构,都涉及到循环,都可无限进行是循环求值是调用本身使用循环结构使用选择结构当循环条件不满足时终止当满足基本条件时终止用计数器控制循环,不停地修改计数器的值,直到不满足条件为止逐渐逼近基本条件而终止,不断地对问题进行简化直到可以直接计算基本问题为止包含多个源文件的程序放到下一次再讲第三十四页,共四十八页,编辑于2023年,星期五编辑函数要注意的事项每一个函数都必须有注释,即使函数短到可能只有几行。每个函数定义结束之后以及每个文件结束之后都要加一个或若干个空行。在一个函数体内,变量定义与函数语句之间要加空行。复杂的函数中,在分支语句,循环语句结束之后需要适当的注释,方便区分各分支或循环体。如果函数中的参数较长,则要进行适当的划分。用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。如:min(),max()第三十五页,共四十八页,编辑于2023年,星期五参数的书写要完整,不要贪图省事只写参数的类型而省略参数名字。如果函数没有参数则用void填充。不要省略返回值的类型,如果函数没有返回值,那么应声明为void类型。函数的功能要单一,不要设计多用途的函数。函数体的规模要小,尽量控制在80行代码之内。相同的输入应当产生相同的输出。尽量避免函数带有“记忆”功能。建议尽量少用static局部变量,除非必需。避免函数有太多的参数,参数个数尽量控制在4个或4个以内。函数名与返回值类型在语义上不可冲突。编辑函数要注意的事项(续)第三十六页,共四十八页,编辑于2023年,星期五小结函数可以作为大型程序的组成模块。每个函数应该实现某个明确的功能。使用参数可以向函数传递数据,通过return让函数返回一个数据。使用函数原型声明函数,以便编译器检查函数调用时所传递的参数个数及类型是否正确。函数可以调用自身,这种调用方式称为递归。有些问题使用递归解决方案,但是递归会在内存使用和时间花费方面效率低下。函数const修饰符也可以修饰函数的返回值,返回值不可被改变。例如:ConstintFun(void);第三十七页,共四十八页,编辑于2023年,星期五请自学本章教材内容并预习下一章的内容与实验请自己做本章的习题与实验体验本章到此结束,谢谢您的光临!THANKYOUVERYMUCH!第三十八页,共四十八页,编辑于2023年,星期五程序设计举例:掷骰子掷骰子问题每个玩家掷两个骰子。每个骰子都有6个面。这些面中包含了1点、2点、3点、4点、5点和6点。当骰子静止下来之后,计算两个朝上的面中的点数和(本次投掷的结果)。如果第一次投掷的结果是7或11,那么这个玩家就获胜。如果第一次投掷的结果是2、3或1、2,那么这个玩家就输了(即庄家获胜)。如果第一次投掷的结果是4、5、6、8、9或10,那么这个结果就是该玩家的“点数”。为了获胜,玩家必须继续掷骰子,直到“掷出了点数”。在掷出点数之前,如果玩家掷出了7,那么玩家就输了。函数第三十九页,共四十八页,编辑于2023年,星期五程序设计举例:掷骰子掷骰子初始设计定义一个函数rollDice,用来模拟掷一次骰子产生两个随机数(1..6),返回它们的和(点数)函数掷第一次胜输掷一次胜输?第四十页,共四十八页,编辑于2023年,星期五程序设计举例:掷骰子掷骰子细化设计定义一个变量保存游戏进展的状态gamestatus0:继续1:胜利(游戏结束)2:失败(游戏结束)函数否rollDice结束?rollDice结束?否是是赢或输第四十一页,共四十八页,编辑于2023年,星期五程序设计举例:掷骰子掷骰子实现(cw0807.c)函数#include<stdio.h>#include<stdlib.h>#include<time.h>introllDice(void);intmain(){

intgameStatus,sum,myPoint;

srand(time(NULL));sum=rollDice();掷第一次第四十二页,共四十八页,编辑于2023年,星期五程序设计举例:掷骰子掷骰子实现函数switch(sum){

case7:c

温馨提示

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

评论

0/150

提交评论