C程序设计第七章函数.ppt
Chapter7-FunctionsOutline7.1Introduction7.2Program Modules in C7.3Math Library Functions7.4Functions7.5Function Definitions7.6Function Prototypes7.7Header Files7.8Calling Functions:Call by Value and Call by Reference7.9Random Number Generation7.10Example:A Game of Chance7.11Storage Classes7.12Scope Rules7.13Recursion7.14Example Using Recursion:The Fibonacci Series7.15Recursion vs.Iteration17.1IntroductionDivideandConquer分而治之ConstructaprogramfromsmallerpiecesorcomponentsEachpiecemoremanageablethantheoriginalprogram函数函数是一段完成特定任务的程序。是一段完成特定任务的程序。2模块化程序设计模块化程序设计基本思想:将一个大的程序按功能分割成一些小模块特点:各模块相对独立、功能单一、结构清晰、接口简单控制了程序设计的复杂性提高元件的可靠性缩短开发周期避免程序开发的重复劳动易于维护和功能扩充开发方法:自上向下,逐步分解,分而治之3C程序结构&C是函数式语言&必须有且只能有一个名为main的主函数&C程序的执行总是从main函数开始,在main中结束&函数不能嵌套定义,可以嵌套调用C是模块化程序设计语言是模块化程序设计语言47.2Program Modules in CFunctionsModulesinCProgramswrittenbycombininguser-definedfunctionswithlibraryfunctionsCstandardlibraryhasawidevarietyoffunctionsMakesprogrammersjobeasier-avoidreinventingthewheel57.2Program Modules in C(II)Functioncalls函数调用Invokingfunctions调用函数Providefunctionnameandarguments(data)FunctionperformsoperationsormanipulationsFunctionreturnsresultsBossasksworkertocompletetaskWorkergetsinformation,doestask,returnsresultInformationhiding:bossdoesnotknowdetails67.3Math Library FunctionsMathlibraryfunctionsperformcommonmathematicalcalculations#includeFormatforcallingfunctionsFunctionName(argument);Ifmultiplearguments,usecomma-separatedlistprintf(%.2f,sqrt(900.0);Callsfunctionsqrt,whichreturnsthesquarerootofitsargumentAllmathfunctionsreturndatatypedoubleArgumentsmaybeconstants,variables,orexpressions77.4FunctionsFunctionsModularizeaprogramAllvariablesdeclaredinsidefunctionsarelocalvariables(局部变量)KnownonlyinfunctiondefinedParametersCommunicateinformationbetweenfunctionsLocalvariablesBenefitsDivideandconquerManageableprogramdevelopmentSoftwarereusabilityUseexistingfunctionsasbuildingblocksfornewprogramsAbstraction-hideinternaldetails(libraryfunctions)Avoidscoderepetition87.5Function DefinitionsFunctiondefinitionformatreturn-value-type function-name(parameter-list)declarations and statementsFunction-name:anyvalididentifierReturn-value-type:datatypeoftheresult(defaultint)void-functionreturnsnothingParameter-list:commaseparatedlist,declaresparameters(defaultint)97.5Function Definitions(II)Functiondefinitionformat(continued)return-value-type function-name(parameter-list)declarations and statementsDeclarationsandstatements:functionbody(block)Variablescanbedeclaredinsideblocks(canbenested)FunctioncannotbedefinedinsideanotherfunctionReturningcontrolIfnothingreturnedreturn;or,untilreachesrightbraceIfsomethingreturnedreturnexpression;101.无参函数的定义形式无参函数的定义形式类型标识符类型标识符 函数名(函数名()说明部分说明部分 语句语句 例如:printstar()printf(“*n”);无参数传递无参数传递有参数传递有参数传递2.有参函数的定义形式有参函数的定义形式 类型标识符类型标识符 函数名(形式参数表列)函数名(形式参数表列)形式参数说明形式参数说明 说明部分说明部分 语句语句 11例int max(int x,int y)int z;z=xy?x:y;return z;/*求x和y二者中大者,x,y为形参*/*形参说明必须在函数体外*/*函数体中变量的说明*/*将z的值作为函数返回值,该值的类型应该和类型标识符确定的函数的类型一致。*/3.空函数的定义形式空函数的定义形式类型标识符类型标识符 函数名函数名()例如:dummy()特点:调用后什么也不做。用处:建立程序结构,在需要时补充功能。127.5 函数参数函数参数1.形式参数和实际参数形式参数和实际参数形式参数形式参数:在定义函数时函数名后面括弧中的变量名,简称形参形参。实际参数实际参数:在调用函数时函数名后面括弧中的表达式,简称实参实参。例main()int a,b,c;scanf(“%d,%d”,&a,&b);c=max(a,b);printf(“Max is%d”,c);int max(int x,int y)int z;z=xy?x:y;return(z);13上例中形参与实参、函数名与返回值之间的关系:上例中形参与实参、函数名与返回值之间的关系:c=max(a,b);-实参实参:在运行时把函数的 max(int x,int y)把值传给函数.结果赋给 函数名 returu(z);形参形参:通知系统 要预留内存位置.14形参调用前不占内存单元,调用时占用,调用后释形参调用前不占内存单元,调用时占用,调用后释放。放。形参是函数的内部变量,只在函数内部才有意义。形参是函数的内部变量,只在函数内部才有意义。对每个形参必须指明其名字和数据类型。对每个形参必须指明其名字和数据类型。实参必须有确定的值,可以是常量,变量或表达式。实参必须有确定的值,可以是常量,变量或表达式。实参与形参的类型个数应一致。实参与形参的类型个数应一致。实参对形参的数据传递是值传递,即单向传递,只实参对形参的数据传递是值传递,即单向传递,只由实参传递给形参,反之不可。调用结束后,只有由实参传递给形参,反之不可。调用结束后,只有形参单元被释放,形参单元被释放,实参单元中的值不变实参单元中的值不变。2.关于参数的几点说明关于参数的几点说明:15返回语句形式:return(表达式);或return表达式;或return;功能:使程序控制从被调用函数返回到调用函数中,同时把返值带给调用函数说明:函数中可有多个return语句若无return语句,遇时,自动返回调用函数若函数类型与return语句中表达式值的类型不一致,按前者为准,自动转换-函数调用转换void型函数例无返回值函数voidswap(intx,inty)inttemp;temp=x;x=y;y=temp;函数的返回值函数的返回值16 函数定义时应该指定函数的类型函数定义时应该指定函数的类型(即函数值即函数值的类型),应该与的类型),应该与return语句的类型一致。语句的类型一致。说明说明:凡不加类型说明的函数,一律自动按整型处理。如果函数类型和return语句的类型不一致,以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。如果函数不返回值,可以将函数定义为“无类型”void(或称“空类型”)。例如:voidprint_star()函数值的类型函数值的类型17Outline1.Function prototype(3 parameters)2.Input values2.1 Call function3.Function definition4.Program Output1/*Fig.7.4:fig07_04.c2Findingthemaximumofthreeintegers*/3#include45intmaximum(int,int,int);/*functionprototype*/67intmain()89inta,b,c;1011 printf(Enterthreeintegers:);12 scanf(%d%d%d,&a,&b,&c);13 printf(Maximumis:%dn,maximum(a,b,c);1415 return0;16 1718/*Functionmaximumdefinition*/19 intmaximum(intx,inty,intz)20 21 intmax=x;2223 if(ymax)24 max=y;2526 if(zmax)27 max=z;2829 returnmax;30 Enterthreeintegers:228517Maximumis:857.6Function PrototypesFunctionprototype函数原型FunctionnameParameters-whatthefunctiontakesinReturntype-datatypefunctionreturns(defaultint)UsedtovalidatefunctionsPrototypeonlyneedediffunctiondefinitioncomesafteruseinprogramintmaximum(int,int,int);Takesin3intsReturnsanintPromotionrules(提升规则)andconversionsConvertingtolowertypescanleadtoerrors197.3 对被调用函数的说明对被调用函数的说明(声明)(声明)对被调用函数说明的前提条件对被调用函数说明的前提条件被调用函数必须是已存在的函数,如用户自定义函数或库函数。2.被调用函数是用户自定义函数的函数说明被调用函数是用户自定义函数的函数说明同变量一样,函数的调用也应该遵循“先说先说明,后使用明,后使用”的原则。如果使用用户自定义函数,而且主调函数和被调用函数在同一个文件中,应该在主调函数中说明被调函数的类型。其说明格式的一般形式如下:20一般形式:一般形式:类型标识符类型标识符 函数名函数名(类型类型1 1,类型,类型2 2,);类型标识符类型标识符 函数名函数名(类型类型1 1 形参形参1 1,类型,类型2 2 形参形参2,);2,);功能:功能:通知编译程序函数值是什么类型,有多少参数及它们各自的类型,为编译程序进行类型检查提供依据。main()float add(float x,float y);float a,b,c;scanf(“%f,%f”,&a,&b);c=add(a,b);printf(“sum is%f”,c);/*定义定义add函数函数*/float add(float x,float y)float z;z=x+y;return(z);对被调用函数的说明作为表达式被调用213.函数说明和函数定义的区别函数说明和函数定义的区别 函数说明函数说明的作用是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查。函数定义函数定义是指对函数功能的确立,包括指定函数名、函数值类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。227.7Header FilesHeaderfilescontainfunctionprototypesforlibraryfunctions,etcLoadwith#include#includeCustomheaderfilesCreatefilewithfunctionsSaveasfilename.hLoadinotherfileswith#includefilename.hReusefunctions23函数概述在C语言中,子程序被称为函数一个C程序一般由多个函数组成,其中必须有一个且仅有一个名为main主函数。C程序总是从main函数开始执行main函数可以调用其它函数,反之不行。有两类函数:标准库函数;用户自定义函数。longsquare(longx)longx_square;x_square=x*x;returnx_square;举例说明函数声明,调用,函数定义,说明部分,执行部分函数名字必须唯一。函数是独立的封闭的。互相不干扰。24例:输入三个整数,计算它们的和并输出运算结果。例:输入三个整数,计算它们的和并输出运算结果。main()int a,b,c,sum;scanf(%d,%d,%d,&a,&b,&c);sum=add(a,b,c);printf(sum=%dn,sum);int add(int x,int y,int z)int s;s=x+y+z;return s;25调用形式函数名(实参表);说明:实参与形参个数相等,类型一致,按顺序一一对应实参表求值顺序,因系统而定(TurboC自右向左)函数的调用函数的调用26函数语句:例printstar();printf(“Hello,World!n”);函数表达式:例m=max(a,b)*2;函数参数:例printf(“%d”,max(a,b);m=max(a,max(b,c);函数的调用方式函数的调用方式27例:用函数计算浮点数例:用函数计算浮点数x的的n次方,其中次方,其中n为为int型型,n=0double power(double x,int n)double p;int i;for(p=i=1;i=n;i+)p=p*x;return p;28例:计算函数的值例:计算函数的值.f(x)=int f(int x)int y;if(x0)y=x-1;else if(x=0)y=1;else y=x+1;return y;X+1X-11X0X=0main()int x;scanf(“%d”,&x);printf(“f(x)=%d”,f(x);297.8Calling Functions:Call by Value and Call by ReferenceUsedwheninvokingfunctionsCallbyvalueCopyofargumentpassedtofunctionChangesinfunctiondonoteffectoriginalUsewhenfunctiondoesnotneedtomodifyargumentAvoidsaccidentalchangesCallbyreferencePassesoriginalargumentChangesinfunctioneffectoriginalOnlyusedwithtrustedfunctionsFornow,wefocusoncallbyvalue30值传递值传递方式方式方式:函数调用时,为形参分配单元,并将实参的值复制到形参中;调用结束,形参单元被释放,实参单元仍保留并维持原值特点:形参与实参占用不同的内存单元单向传递参数传递方式参数传递方式31711x:y:调用前:调用结束:711x:y:/*swap.c*/#includemain()intx=7,y=11;printf(x=%d,ty=%dn,x,y);printf(swapped:n);swap(x,y);printf(x=%d,ty=%dn,x,y);swap(inta,intb)inttemp;temp=a;a=b;b=temp;调用:711a:b:711x:y:swap:711x:y:117a:b:temp例例 交换两个数交换两个数32方式:函数调用时,将数据的存储地址作为参数传递给形参特点:形参与实参占用同样的存储单元“双向”传递实参和形参必须是地址常量或变量函数的地址传递函数的地址传递33/*swap.c*/swap(p1,p2)int*p1,*p2;int p;p=*p1;*p1=*p2;*p2=p;main()int a,b;scanf(%d,%d,&a,&b);printf(“a=%d,b=%dn”,a,b);printf(“swapped:n”);swap(&a,&b);printf(”a=%d,b=%dn,a,b);a59b调前:a59b调swap:p1&a&bp2a95b交换:p1&a&bp2a95b返回:例子图解例例 交换两个数交换两个数34#includelongsum(inta,intb);longfactorial(intn);main()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);文件包含编译预处理命令函数类型说明函数定义函数调用函数调用函数返回值形参实参例子解析例子解析357.9Random Number GenerationrandfunctionLoadReturnsrandomnumberbetween0andRAND_MAX(atleast32767)i=rand();PseudorandomPresetsequenceofrandomnumbersSamesequenceforeveryfunctioncallScalingTogetarandomnumberbetween1andn1+(rand()%n)rand%nreturnsanumberbetween0andn-1Add1tomakerandomnumberbetween1andn1+(rand()%6)/numberbetween1and6367.9Random Number Generation(II)srand functionTakesanintegerseed-jumpstolocationinrandomsequencesrand(seed);srand(time(NULL);/loadtime(NULL)-timeprogramwascompiledinsecondsrandomizestheseed37Outline1.Initialize seed2.Input value for seed2.1 Use srand to change random sequence2.2 Define Loop 3.Generate and output random numbers 1/*Fig.7.9:fig07_09.c2Randomizingdie-rollingprogram*/3#include4#include56intmain()78inti;9unsignedseed;10 11 printf(Enterseed:);12 scanf(%u,&seed);13 srand(seed);14 15 for(i=1;i=10;i+)16 printf(%10d,1+(rand()%6);17 18 if(i%5=0)19 printf(n);20 2122 return0;23 OutlineProgram OutputEnterseed:8672461611362Enterseed:676146216164 Enterseed:6761462161647.10 Example:A Game of ChanceCrapssimulatorRulesRolltwodice7or11onfirstthrow,playerwins2,3,or12onfirstthrow,playerloses4,5,6,8,9,10-valuebecomesplayerspointPlayermustrollhispointbeforerolling7towin40Outline1.rollDice prototype1.1 Initialize variables1.2 Seed srand2.Define switch statement for win/loss/continue2.1 Loop1/*Fig.7.10:fig07_10.c2Craps*/3#include4#include5#include67introllDice(void);89intmain()10 11 intgameStatus,sum,myPoint;1213 srand(time(NULL);14 sum=rollDice();/*firstrollofthedice*/1516 switch(sum)17 case7:case11:/*winonfirstroll*/18 gameStatus=1;19 break;20 case2:case3:case12:/*loseonfirstroll*/21 gameStatus=2;22 break;23 default:/*rememberpoint*/24 gameStatus=0;25 myPoint=sum;26 printf(Pointis%dn,myPoint);27 break;28 2930 while(gameStatus=0)/*keeprolling*/31 sum=rollDice();32Outline2.2 Print win/lossProgram Output33 if(sum=myPoint)/*winbymakingpoint*/34 gameStatus=1;35 else36 if(sum=7)/*losebyrolling7*/37 gameStatus=2;38 3940 if(gameStatus=1)41 printf(Playerwinsn);42 else43 printf(Playerlosesn);4445 return0;46 4748 introllDice(void)49 50 intdie1,die2,workSum;5152 die1=1+(rand()%6);53 die2=1+(rand()%6);54 workSum=die1+die2;55 printf(Playerrolled%d+%d=%dn,die1,die2,workSum);56 returnworkSum;57 Playerrolled6+5=11PlayerwinsOutlineProgram OutputPlayerrolled6+6=12PlayerlosesPlayerrolled4+6=10Pointis10Playerrolled2+4=6Playerrolled6+5=11Playerrolled3+3=6Playerrolled6+4=10PlayerwinsPlayerrolled1+3=4Pointis4Playerrolled1+4=5Playerrolled5+4=9Playerrolled4+6=10Playerrolled6+3=9Playerrolled1+2=3Playerrolled5+2=7Playerloses嵌套调用C规定:函数定义不可嵌套,但可以嵌套调用函数main()调用函数a结束a函数b函数调用函数b函数的嵌套与递归调用函数的嵌套与递归调用44#include int dif(int x,int y,int z);int max(int x,int y,int z);int min(int x,int y,int z);void main()int a,b,c,d;scanf(%d%d%d,&a,&b,&c);d=dif(a,b,c);printf(Max-Min=%dn,d);int dif(int x,int y,int z)return max(x,y,z)-min(x,y,z);int max(int x,int y,int z)int r;r=xy?x:y;return(rz?r:z);int min(int x,int y,int z)int r;r=xy?x:y;return(rz?r:z);main()调用函数dif输出结束dif函数max函数调用函数max调用函数minmin函数例例 求三个数中最大数和最小数的差值求三个数中最大数和最小数的差值45定义:函数直接或间接的调用自身叫函数的递归调用f()调f调f2调f1f1()f2()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);递归调用递归调用46Recursion递归递归 RecursivefunctionsFunctionthatcallsitselfCanonlysolveabasecaseDividesupproblemintoWhatitcandoWhatitcannotdo-resemblesoriginalproblemLaunchesanewcopyofitself(recursionstep)EventuallybasecasegetssolvedGetspluggedin,worksitswayupandsolveswholeproblem47Recursion(II)Example:factorial:阶乘5!=5*4*3*2*1Noticethat5!=5*4!4!=4*3!.CancomputefactorialsrecursivelySolvebasecase(1!=0!=1)thenplugin2!=2*1!=2*1=2;3!=3*2!=3*2=6;48#includeintfac(intn)intf;if(n0)printf(n0,dataerror!);elseif(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);例求n的阶乘49Example Using Recursion:The Fibonacci SeriesFibonacciseries:0,1,1,2,3,5,8.Eachnumbersumoftheprevioustwofib(n)=fib(n-1)+fib(n-2)-recursiveformulalongfibonacci(longn)if(n=0|n=1)/basecasereturnn;elsereturnfibonacci(n-1)+fibonacci(n-2);50Example Using Recursion:The Fibonacci Series(II)f(3)f(1)f(2)f(1)f(0)return1return1return0return+return51Outline1.Function prototype1.1 Initialize variables2.Input an integer2.1 Call function fibonacci2.2 Output results.3.Define fibonacci recursively Program Output1/*Fig.7.15:fig07_15.c2Recursivefibonaccifunction*/3#include45longfibonacci(long);67intmain()89longresult,number;1011 printf(Enteraninteger:);12 scanf(%ld,&number);13 result=fibonacci(number);14 printf(Fibonacci(%ld)=%ldn,number,result);15 return0;16 1718/*Recursivedefinitionoffunctionfibonacci*/19 longfibonacci(longn)20 21 if(n=0|n=1)22 returnn;23 else24 returnfibonacci(n-1)+fibonacci(n-2);25 Enteraninteger:0Fibonacci(0)=0Enteraninteger:1Fibonacci(1)=1OutlineProgram OutputEnteraninteger:2Fibonacci(2)=1Enteraninteger:3Fibonacci(3)=2Enteraninteger:4Fibonacci(4)=3Enteraninteger:5Fibonacci(5)=5Enteraninteger:6Fibonacci(6)=8Enteraninteger:10Fibonacci(10)=55Enteraninteger:20Fibonacci(20)=6765Enteraninteger:30Fibonacci(30)=832040Enteraninteger:35Fibonacci(35)=9227465例例7.7 用函数递归法以字符串形式输出一个用函数递归法以字符串形式输出一个整数整数54Recursion vs.Iteration(递归(递归 vs.迭代)迭代)RepetitionIteration:explicitloopRecursion:repeatedfunctioncallsTerminationIteration:loopconditionfailsRecursion:basecaserecognizedBothcanhaveinfiniteloopsBalanceChoicebetweenperformance(iteration)andgoodsoftwareengineering(recursion)55变量的作用域和生存期变量的作用域和生存期变量的作用域指一个范围,在这个范围内程序的各个部分都可以访问该变量(可见的)。#include int x=999;/*Global Variable*/void print_value(void);void main()printf(%dn,x);print_value();void print_value(void)printf(%dn,x);56变量的属性数据类型:变量所持有的数据的性质(操作属性)存储属性:存储属性:存储器类型:寄存器、静态存储区、动态存储区生存期生存期:变量在某一时刻存在-静态变量与动态变量作用域作用域:变量在某区域内有效-局部变量与全局变量变量的存储类型auto -自动型register-寄存器型static -静态型extern -外部型变量定义格式:存储类型 数据类型 变量表;概述变量是对程序中数据的存储空间的抽象如:int sum;auto int a,b,c;register int i;static float x,y;变量的存储属性变量的存储属性57Storage ClassesStorage class specifiersStorageduration-howlonganobjectexistsinmemoryScope-whereobjectcanbereferencedinprogramLinkage-whatfilesanidentifierisknownAutomatic storageObjectcreatedanddestroyedwithinitsblockauto:defaultforlocalvariablesautodoublex,y;register:triestoputvariableintohigh-speedregistersCanonlybeusedforautomaticvariablesregisterintcounter=1;58局部变量-内部变量定义:在函数内定义,只在本函数内有效说明:main中定义的变量只在main中有效不同函数中同名变量,占不同内存单元形参属于局部变量可定义在复合语句中有效的变量局部变量可用存储类型:autoregisterstatic(默认为auto)floatf1(inta)intb,c;.charf2(intx,inty)inti,j;main()intm,n;.a,b,c有效x,y,i,j有效m,n有效例不同函数中同名变量main()inta,b;a=3;b=4;printf(main:a=%d,b=%dn,a,b);sub();printf(main:a=%d,b=%dn,a,b);sub()inta,b;a=6;b=7;printf(sub:a=%d,b=%dn,a,b);例复合语句中变量#defineN5main()inti;intaN=1,2,3,4,5;for(i=0;iN/2;i+)inttemp;temp=ai;ai=aN-i-1;aN-i-1=temp;for(i=0;iN;i+)printf(%d,ai);运行结果:54321例复合语句中变量#defineN5main()inti;intaN=1,2,3,4,5;for(i=0;iN/2;i+)i