模块化程序设计——函数孙小松1C语言程序设计第6章模块化程序设计--函数2§6.1函数的概念C程序结构●C程序结构如图所示1.一个C程序可以分为若干个函数2.每个程序有且只有一个主函数(main),其他都是子函数3.子函数可以相互调用,但主函数不能被调用4.一个C源程序由一个或多个文件构成,每个文件就是一个编译单位C语言程序设计第6章模块化程序设计--函数3●说明:1.一个C程序的执行从主函数(main)开始,调用其他函数后仍回到main主函数结束.2.每个子函数都是平行的,任何子函数都不从属于其他函数3.从用户角度,函数可以分为:☆标准函数,即库函数☆用户自定义函数4.从函数形式可以分为:☆无参函数:printstar()☆有参函数:printf(“hello”)#includestdio.hvoidprintStar(){printf(“*******************\n”);}voidprintMessage(){printf(“Hello,world.\n”);printStar();}voidmain(){printStar();printMessage();}C语言程序设计第6章模块化程序设计--函数4函数定义的一般形式●函数定义的一般形式:类型说明函数名([形式参数说明]){函数体}形式参数说明方法:数据类型变量名[,类型变量名]●无参数函数定义形式:类型说明函数名(){函数体}voidprintHello(){printf(“hello!\n”);}●有参数函数定义形式:类型说明函数名(形式参数说明){函数体}intsum(intx,inty){intz;z=x+y;return(z);}C语言程序设计第6章模块化程序设计--函数5●函数体一般情况下,函数体有两部分组成:{[局部变量说明]语句;}局部变量说明:函数体内的变量.其有效范围仅在本函数体内起作用,离开本函数无意义.intsum(intx,inty){intz;//局部变量定义z=x+y;return(z);}C语言程序设计第6章模块化程序设计--函数6函数的参数和函数的值●一个程序由若干个函数组成,各函数调用时经常要传递一些数据,即调用函数把数据传递给被调用函数,经过被调用函数处理后,得到一个确定的结果,在返回调用函数时,将结果带回调用函数.#includestdio.hintmax(intx,inty){intz;z=(xy)?x:y;return(z);}voidmain(){inta,b,c;scanf(“%d%d”,&a,&b);c=max(a,b);printf(“maxis%d\n”,c);}主函数子函数..c=max(a,b);..intmax(intx,inty)...return(z);a,bz各函数之间数据往来通过参数传递和返回语句实现C语言程序设计第6章模块化程序设计--函数7函数参数:用于函数间数据的传递形式参数:定义函数时给出的参数实际参数:调用函数时给出的参数#includestdio.hintmax(intx,inty){intz;z=(xy)?x:y;return(z);}voidmain(){inta,b,c;scanf(“%d%d”,&a,&b);c=max(a,b);printf(“maxis%d\n”,c);}对于函数max有两个形式参数x,y形式参数x和y只在max函数中使用a,b是主函数中定义的变量,当main函数调用max函数时.a,b成为max的实际参数调用时,实际参数的值赋给形参进行处理例:max接受到两个值:2389max返回89一、形式参数和实际参数C语言程序设计第6章模块化程序设计--函数8#includestdio.hintmax(intx,inty){intz;z=(xy)?x:y;return(z);}voidmain(){inta,b,c;scanf(“%d%d”,&a,&b);c=max(a,b);printf(“maxis%d\n”,c);}说明:1.定义函数时,必须说明形参的类型,形参只能是变量(包括数组).不能是常量或表达式2.函数被调用之前,形参和子函数中的变量不占内存,调用结束返回,形参所占的内存被收回.3.实参可以是常量、变量或表达式.因为传递过来的是具体数值.4.实参和形参类型必须一致(或可以安全转换).5.C语言中,实参和形参传递的是”按值传递”,即单向传递,只与参数相对位置有关,而与变量名无关intb,intaintc;c=(ab)?a:b;return(c);1320main-amain-bmax-amax-b1320C语言程序设计第6章模块化程序设计--函数9#includestdio.hintsum(inta,intb){a=a+b;b=a+b;return(a);}voidmain(){inta=1,b=3,c;c=sum(a,b);printf(“sumof%d,%dis%d\n”,a,b,c);}阅读下面程序,写出运行结果函数被调用之前,形参和子函数中的变量不占内存,调用结束返回,形参所占的内存被收回.实参和形参传递的是”值传递”,即单向传递,只与参数相对位置有关,而与变量名无关sumof1,3is4C语言程序设计第6章模块化程序设计--函数10二、函数返回值#includestdio.hintmax(intx,inty){intz;z=(xy)?x:y;return(z);}voidmain(){inta,b,c;scanf(“%d%d”,&a,&b);c=max(a,b);printf(“maxis%d\n”,c);}函数值也就是函数的返回值,是一个具体确定的值.①函数使用return语句返回值。②一个函数内可以有多个return语句,执行到任何return语句,函数都将立即返回到调用函数if(xy)return(x);elsereturn(y);③return后面的()可以省略,可以返回一个表达式,先求解表达式的值,再返回.intmax(intx,inty){returnxy?x:y;}1.返回函数值的方法C语言程序设计第6章模块化程序设计--函数11#includestdio.hintmax(intx,inty){intz;z=(xy)?x:y;return(z);}voidmain(){inta,b,c;scanf(“%d%d”,&a,&b);c=max(a,b);printf(“maxis%d\n”,c);}2.函数值的类型①函数的类型即函数值的类型.例如,函数max是int型,函数的返回值也是int型.②省略了类型说明的函数就是int型.③return中表达式的值一般和函数类型相同.④如果不一致,则需要进行类型转换.以函数类型为准.C语言程序设计第6章模块化程序设计--函数123.不需要返回的函数①如果函数中没有return,认为是一个过程,可以使用类型void.②如果一个函数被声明void类型,就不允许再引用它的返回值。只能单纯调用它。#includestdio.hvoidprintStar(){printf(“*******************\n”);}voidprintMessage(){printf(“Hello,world.\n”);printStar();}voidmain(){printStar();printMessage();}C语言程序设计第6章模块化程序设计--函数13函数的调用一、函数调用一般形式一般形式:函数名(实参列表)说明:①如果调用无参函数,实参表列可以忽略,但括号不能省.②实参个数和形参个数相同.③实参和形参类型一一对应,必要时会进行类型转换.注意:不同系统中,实参的计算顺序不同.一般认为从右到左计算和赋值.一般在调用函数前计算出实参的值例1读程序,写出结果#includestdio.hintf(inta,intb){intc;if(ab)c=1;elseif(a==b)c=0;elsec=-1;returnc;}voidmain(){inti=2,p;p=f(i,++i);printf(“%d”,p);}C语言程序设计第6章模块化程序设计--函数14二、函数调用方式1、函数语句形式为:函数(实参表列);例如:printMessage();printf(“%d”,p);说明:这种方式不要求函数带返回值,函数只执行一定操作.2、函数表达式函数的返回值参与运算例如:m=max(a,b);m=3*max(a,b);printf(“%d”,max(a,b));说明:这种方式的函数不能用于void类型C语言程序设计第6章模块化程序设计--函数15三、函数调用的执行过程①从右到左的顺序,计算实参中各表达式值.②按照位置,将实参的值一一传递给形参.③执行被调用函数.④当遇到return(表达式)语句时,计算表达式的值并返回主调函数.例2读程序,写出结果#includestdio.hintiabs(floatx){return(x0?x:-x);}voidmain(){floatx=-0.6,y;y=iabs(2*x);printf(“x=%f,iabs(x)=%f\n”,x,y);}1234X=-0.600000,iabs(x)=1.000000C语言程序设计第6章模块化程序设计--函数16四、函数的原形在程序中调用函数需满足以下条件:①被调用函数必须存在,且必须遵循“先定义后使用”的原则②如果被调用函数的定义在主调函数之后,可以在调用之前给出原形说明.原形说明:类型说明函数名(参数类型,参数类型…)C语言程序设计第6章模块化程序设计--函数17函数的嵌套调用嵌套调用是指在一个函数的函数体中又调用了其他函数.程序执行过程:第一层第二层第三层main()printStar(){{printStar();……}printfMessage()printMessage();{……printStar();printStar();{……}}}结束#includestdio.hvoidprintStar(){printf(“*******************\n”);}voidprintMessage(){printf(“Hello,world.\n”);printStar();}voidmain(){printStar();printMessage();}C语言程序设计第6章模块化程序设计--函数18例3编程求)!(!!mnmnCmn分析:重复三次不同的阶乘运算,只是每次的值不同.将求阶乘的过程编程一个函数fac,以不同的参数值来调用facfackk!#includestdio.h#includemath.hfloatfac(intk);{floatt=1.0;inti;for(i=2;i=k;i++)t*=i;returnt;}voidmain(){floatc;intm,n;printf(“inputm,n:”);scanf(“%d%d”,&m,&n);c=fac(n)/(fac(m)*fac(n-m));printf(“%.0f\n”,c);}C语言程序设计第6章模块化程序设计--函数19•许多数学函数都是使用递归调用形式定义的:)!1(1!nnn函数的递归调用当n=1时当n1时11nnxxx当n=0时当n!=1时C语言程序设计第6章模块化程序设计--函数20•函数的递归调用是指在调用一个函数时又直接或间接调用函数本身.•直接调用•间接调用•递归调用必须引入一个循环条件控制递归结束,否则进入死循环.C语言程序设计第6章模块化程序设计--函数21•例4有5个人坐在一起,问第5个人多少岁?答:比第4个人大2岁;第4个人说他比第三个人大2岁;第3个人比第2个人大2岁,第2个人比第1个人大2岁.而第1个人有10岁.问第5个人多少岁?•计算公式:2)1(10)(nagenage(n=1)