16.1求周长与面积6.2验证歌德巴赫猜想6.3求最大公约数6.4Fibonacci数列6.5编译预处理6.6综合应用实例第6章函数26.1求周长与面积6.1.1程序解析[例6-1]输入圆的半径,通过函数计算并输出圆的周长及面积。[程序代码]#includestdio.hconstfloatPI=3.14159voidmain(){floats,lr;printf(“请输入圆的半径:”);scanf(“%f”,&r);l=perimeter(r);s=area(r);printf(l=%fs=%f\n”,l,s);}floatperimeter(floatr){return(2*PI*r);}floatarea(floatr){floats;s=PI*r*r;returns;}3函数:功能独立,反复使用的代码段(1)一个源程序文件由一个或多个函数构成。(2)程序是由一个或多个源程序文件组成,以源程序文件为单位进行编译。(3)C程序的执行从main函数开始,在main函数中结束。(4)函数不能嵌套定义,可相互调用,但不能调用main函数。6.1求周长与面积6.1.2程序的结构main()函数perimeter()函数area()函数printf()函数主调函数被调函数被调函数被调函数函数的返回41.从函数定义的角度(1)标准函数,即库函数。(2)用户自定义函数。2.从函数参数的角度(1)无参函数。函数定义、函数说明、函数调用均不带参数。(2)有参函数。函数定义、函数说明时有形式参数。函数调用时有实际参数(简称实参)。3.函数分类的其他角度(1)返回值:有返回值和无返回值函数;(2)返回值类型:整型、实型、字符型和指针型函数等。6.1.3函数的分类56.1.4函数的定义1.无参函数的定义类型说明符函数名(){声明部分语句执行部分语句}类型说明符和函数名()称为函数头。类型是指该函数返回值的类型,系统隐含为int型。函数名是用户定义的标识符,函数名后面必须有一对括号()。花括号{}中的内容称为函数体,由声明部分和执行部分语句序列组成。函数的运算结果通过return语句返回,格式为:return(表达式);或return表达式;6【例6-2】编写求两个整数的较大值函数max()。voidmain(){max();}#includestdio.hvoidmax(){inta,b,c;scanf(%d,%d,&a,&b);z=xy?x:y;printf(max=%d\n,c);}输入、输出和计算操作均在子函数中完成无参函数一般不需要返回值,应将函数值的类型定义为void,即空类型,以确定函数返回时不带回任何值。7【例6-2】包含无参但有返回值函数的C程序例。intmain(){intm;m=max1();printf(max=%d\n,m);return0;}#includestdio.hintmax1(){inta,b,c;scanf(%d,%d,&a,&b);c=ab?a:b;return(c);}输入和计算操作在子函数中完成;输出在主函数中8类型函数名(类型形参1,类型形参2,…){声明部分语句;执行部分语句;}2.有参函数有参函数定义在函数头部多了形式参数和形式参数类型说明的内容。形参可以是任何类型的变量,参数间用逗号分隔。在函数调用时,主调函数将实际参数值赋予这些形参变量。9【例6-2】包含有参有返回值函数的C程序示例。voidmain(){inta,b,m;scanf(%d,%d,&a,&b);m=max2(a,b);printf(max=%d\n,m);}#includestdio.hintmax2(intx,inty){intz;z=xy?x:y;return(z);}计算操作在子函数中完成;输入输出在主函数中10【例6-2】有参无返回值函数的C程序示例。voidmain(){inta,b;scanf(%d,%d,&a,&b);max2(a,b);}#includestdio.hvoidmax3(intx,inty){intz;z=xy?x:y;printf(max=%d\n,z);}计算和输出操作在子函数中完成;输入在主函数中11#includestdio.hvoidpyramid(intn){inti,j;for(i=1;i=n;i++){for(j=1;j=n-i;j++)printf(“”);for(j=1;j=i;j++)printf(“%d”,i);printf(\n);}}voidmain(){intn;scanf(%d,&n);pyramid(m);}【例6-3】编写函数,输出n以内的数字金字塔。[分析]:–函数体为图形输出,函数设置为有参无返回类型–形参为整型变量n。12“空函数”定义的一般形式类型说明符函数名(){}例如:voidkhs(){}主函数中可有调用语句khs();但没有任何作用;“空函数”一般为今后程序中增加函数预留位置。3.空函数13函数的首部写成不止一行的形式。类型说明符函数名(形参1,形参2,…)类型形参1,类型形参2,…;{说明部分语句;执行部分语句;}4.传统风格的函数定义【例6-2】中max2可以写成intmax2(x,y)intx,y;{intz;z=xy?x:y;return(z);}146.1.5函数设计的基本原则1、函数的规模要小,尽量控制在50行代码以内。2、函数的功能要单一,不要让它身兼数职。3、每个函数只有一个入口和出口。4、在函数入口处清楚地定义函数的行为。5、在函数的入口处对参数的有效性进行检查。6、当函数需要返回值时,应确保函数中的所有控制分支都有返回值;函数无返回值时需在void中声明。156.2验证哥德巴赫猜想6.2.1程序解析[例6-4]验证哥德巴赫猜想,输入一个大于6的偶数,要求验证其等于两个素数之和。[分析]:–需要测试大于6的偶数s是否存在a和s-a均为素数,可以考虑定义一个判断素数的子函数。(2=a=s/2)–子函数的形参为整型变量n,若为素数,则返回1,否则返回0。16#includestdio.hintprime(intn){inti,j;if(n=1)return0;for(i=1;in;i++)if(n%i==0)return0;//找到一个能被n整除的数,不是素数return1;}voidmain(){ints,a;intprime(intn);scanf(%d,&s);for(a=2;a=s/2;a++)if(prime(a)&&prime(s-a))printf(“%d=%d+%d\n”,s,a,s-a);}176.2.2函数调用和参数传递1.函数调用函数名(实际参数表)【说明】①实际参数表中有多个实参用逗号分隔;②实参与形参的个数应相同,类型应对应;③调用无参函数,函数名后的一对园括号“()”不能省略。voidmain(){ints,a;…prime(a);…}Intprime(intn){……}调用返回函数调用的流程18①为被调函数局部变量(含定义的变量和形参)开辟存储单元。②将实参的值复制给形参。③流程从主调函数的调用处转移到被调函数,执行被调函数体中语句序列。④当执行到被调函数“return(表达式);”语句时,返回到主调函数,将表达式的值作为函数值替换“函数名(实际参数表)”,结束被调函数的执行;如无return语句,则遇函数体右花括号“}”结束被调函数的执行。⑤释放局部变量的存储单元,流程从被调函数转移到主调函数的调用处。⑥继续从主调函数的调用处向下执行。函数调用流程192.函数调用的应用形式(1)函数调用语句;pyramid(n)(2)出现在表达式中;if(prime(a)&&prime(s-a))(3)作为另一个函数调用的实际参数.max(max(a,b),c)3.函数调用时实参求值的顺序(从右到左)【例6-5】考察函数调用时实参求值顺序#includestdio.hmain(){intk=1,j;j=f(k,++k);printf(%d\n,j);}intf(inta,intb){intc=-1;if(ab)c=1;elseif(a==b)c=0;return(c);}20return(表达式);或return表达式;功能:1、计算表达式的值,并作为函数值返回给主调函数。2、一个函数中允许有多个return语句,但每次调用只执行一个return语句,只能返回一个函数值。6.2.3函数的返回值说明:(1)return语句以没有表达式,如:return;(2)如果不需要返回函数值,被调函数可以没有return语句,程序执行到函数体的右括号“}”时自动返回。(3)函数返回值的类型和函数定义的类型应保持一致。如果不一致,以函数定义类型为准。(4)如果函数的返回值是整型,则在函数定义时可省略类型说明。(5)为了明确表示“不带回值”,可将函数定义为void“空类型”。216.2.4函数的声明函数调用需要以下条件:(1)该函数必须存在;(2)自定义函数调用时一般要声明;(3)调用库函数时,要#include命令声明形式(1)类型说明符函数名(类型形参1,类型形参2,…);形参变量名可省,如:intmax(int,int);(2)类型说明符函数名();省略对被调函数的声明:(1)函数定义在前,调用在后;(2)在函数的外部已声明;(3)整型函数,在.c中可以不声明,但.cpp中要声明。22#includestdio.hmain(){inta,b;floataver(intx,inty);floatave;scanf(%d,%d,&a,&b);ave=aver(a,b);printf(ave=%7.2f\n,ave);}floataver(intx,inty){floatz;z=(x+y)/2.0;returnz;}【例6-6】对被调函数的声明236.3.1程序解析[例6-7]求两个自然数的最大公约数和最小公倍数。[分析]:–可定义两子函数用于求最大公约数和最小公倍数:gcd(a,b)和lcm(a,b)–求最大公约数有三种算法:穷举法,欧几里得算法和递归算法。6.3求最大公约数24#includestdio.hvoidmain(){intgcd(inta,intb),lcm(int,int);intx,y,g,l;printf(pleaseinputtwointegers:);scanf(%d%d,&x,&y);g=gcd(x,y);l=lcm(x,y);printf(“gcd=%d,lcm=%d\n”,g,l);}intgcd(intx,inty)//穷举法{inti;if(xy)i=x;elsei=y;for(i=x;i=1;i--)if(x%i==0&&y%i==0)returni;}intlcm(intx,inty){return(x*y/gcd(x,y));}嵌套调用gcd()函数25intgcd(intx,inty)//欧几里得法{intr;while(y!=0){r=x%y;x=y;y=r;}returnx;}intgcd(intx,inty)//递归法{if(x%y==0)returny;elsereturn(gcd(y,x%y));}266.3.2函数的嵌套调用C语言中函数的定义都是相互平行、相互独立。函数不能嵌套定义,但可以嵌套调用。【例6-8】分析下面程序,其功能是通过函数计算s=1!+2!+3!+…+10!。27doublesum(intm){doubles=0,mul();inti;for(i=1;i=m;i++)s=s+mul(i);returns;}doublemul(intn){doublet=1,j;for(j=1;j=n;j++)t=t*j;returnt;}#includestdio.hmain