《函数与模块化程序设计.ppt》由会员分享,可在线阅读,更多相关《函数与模块化程序设计.ppt(65页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、课前思考1 一个学校,有什么样的机构设置,从职能上有什么特点,学校的领导机关主要负责什么?各机构间是怎么样协调工作的?2如果你是一个公司或企业的老板,需要处理哪些日常事务,对于这些事务你是全部自己处理,还是分配给别人处理?如果企业日益壮大,你是否需要设置相应的一些职务部门,想想要设置哪些部门,这些部门都干什么工作?在思考自己为什么要这门做?3如果要你设计一个比较复杂的C语言程序,那么你在分析程序的功能需求时,你怎么去安排这些功能的实现模块,是全部放在main函数中呢,还是按功能设计成各自独立的模块,然后在main函数中按需求调用呢?课前思考4 一个功能明确的函数模块(职能部门)应改提供明确的服
2、务,思考一下应该有什么样具体的接口(就像服务窗口所能提供服务和要求)?第第六六章章 函数与模块化程函数与模块化程序设计序设计 本章主要内容本章主要内容 函数的定义和调用函数的定义和调用变量的作用域与存储类型变量的作用域与存储类型利用函数进行模块化程序设计利用函数进行模块化程序设计6.1 6.1 函数的定义和调用函数的定义和调用6.1.1 概述概述模块与函数1.功能模块求解较小问题的算法和程序称作“功能模块”,各功能模块可以先单独设计,然后将求解所有子问题的模块组合成求解原问题的程序。“自顶向下”的模块化程序设计方法:将一个大问题分解成多个解决小问题的模块的设计思想。2.由功能模块组成程序的结构
3、图由功能模块组成程序的结构图:主控模块主控模块模块模块1_1模块模块1_n模块模块2_1模块模块2_n模块模块n_1模块模块n_n模块模块1模块模块2模块模块n3.函数函数:完成相对独立功能的程序完成相对独立功能的程序【例6-1】输入年月日,计算出该日为该年的第几天。主控模块主控模块判断闰年判断闰年求某月的天数求某月的天数输输出出输输入入求总天数求总天数图图6-2 6-2 程序结构图程序结构图程序实现:(1)判断闰年。int leap(int year)int lp;lp=(year%4=0&year%100!=0|year%400=0)?1:0;return lp;(2)求某月的天数。int
4、 month_days(int year,int month)int ds,d;switch(month)case 1:case 3:case 5:case 7:case 8:case 10:case 12:d=31;break;case 2:d=leap(year)?29:28;break;default:d=30;return d;(3)求天数和。int days(int year,int month,int day)int i,ds=0;for(i=1;i0)/幂指数幂指数0for(;n0;n-)/求求n个个x的乘积的乘积m*=x;elsem=1;/n=0时,时,m的的0次幂次幂=1re
5、turn(m);函数函数通过通过return或或指针指针返回结果返回结果,若若return中表达式类型与中表达式类型与函数类型函数类型不一致,则转换不一致,则转换为函数类型。无返回值的函数定义为为函数类型。无返回值的函数定义为void类型类型一般调用形式是:一般调用形式是:函数名函数名(实参表实参表)6.1.3 6.1.3 函数的调用函数的调用 当调用函数时,把被调用函数当成了当调用函数时,把被调用函数当成了“黑箱黑箱”,调,调用者只要知道被调用函数的名字、功能、输入输出数据类用者只要知道被调用函数的名字、功能、输入输出数据类型,个数以及前后顺序。实参和形参的个数、数据类型、型,个数以及前后顺
6、序。实参和形参的个数、数据类型、顺序要与形参完全一致。顺序要与形参完全一致。Eg:fabs(x);Eg:fabs(x);strcmp(str1,str2);strcmp(str1,str2);形参形参:在定义函数的时候出现的需要预先:在定义函数的时候出现的需要预先知道的参数;知道的参数;int fun (int a,int b)返回返回a的的b次次 main()实参实参:在调用的时候传递的数,已经具有:在调用的时候传递的数,已经具有了实际的值。了实际的值。eg:main()int x=3,y=5;int var=fun(5,3);int var=fun(x,y);(1)直直接接以以函函数数引引
7、用用(调调用用)语语句句的的形式出现形式出现例如:例如:scanf(%d%d%d“,&i,&j,&k);call_function(i,j,k);(2)函数函数在表达式中在表达式中出现出现例如:例如:y=8.25*min(x,y)*function(n);(3)在函数引用中在函数引用中以实参的形式以实参的形式出现出现例如:例如:y=cos(tg(x);/也称嵌套调用也称嵌套调用相当于:相当于:var=tg(x);y=cos(var);main()a()b()调用调用a()调用调用b()END函数的嵌套调用函数的嵌套调用调用一个函数过程中又调用了另一个函数调用一个函数过程中又调用了另一个函数值值
8、的的传传送送:先先求求实实参参值值,然然后传送给相应的形参后传送给相应的形参6.1.4 函数间的信息传递方式函数间的信息传递方式 信息信息传递传递方式方式地地址址传传送送:实实参参是是地地址址名名(如如数数组组名名)或或指指针针名名,则则将将该该地地址或指针传送给相应形参址或指针传送给相应形参(1)(1)当当形形参参是是变变量量名名时时,实实参参可可以以是是一一个个可可求求值值的的表表达达式式(包包括括常数、已赋值的变量名常数、已赋值的变量名)实参实参形参之间的信息传递形参之间的信息传递 下下面面的的代代码码试试图图实实现现数数据据顺顺序序交交换换,分分析代码特点。析代码特点。#include
9、“stdio.h”swap(floatf1,floatf2)floattemp;temp=f1;f1=f2;f2=temp;voidmain()floatx,y;scanf(”%f%f”,&x,&y);printf(”x=%fy=%f”,x,y);printf(”n-doswap-n”);swap(x,y);printf(”x=%fy=%fn”,x,y);3.456 7.89 x=3.456000 y=7.890000-do swap-x=3.456000 y=7.890000分析:分析:在调用函数的时候,才给形参分配内存空在调用函数的时候,才给形参分配内存空间。间。f1和和f2的值发生了变化
10、,但是没有影响的值发生了变化,但是没有影响到到x和和y的值。的值。(2)实参可以是调用另一个函数的返回值实参可以是调用另一个函数的返回值#include“stdio.h”voidmain()intj;doublex,y,power();doubleadd_pow,sub_pow;scanf(“%f%f”,&x,&y);for(j=1;j0)return(1);elseif(x=0)return(0);elsereturn(-1);函数调用结果的返回函数调用结果的返回 可根据需要设置多个可根据需要设置多个return语句,但调用语句,但调用函数时仅执行其中一函数时仅执行其中一个,所以最多只返回个
11、,所以最多只返回一个值一个值可以作为可以作为fabs()中被调中被调用的函数。用的函数。float fabs(float x)int flag;flag=sign(x);x*=flag;return(x);main()float x=-4.5,y;y=fabs(x);sign函数函数作为作为fabs()中被调用的函数。中被调用的函数。2 2 利用全局变量传递数据利用全局变量传递数据#include“stdio.h”intsum;plus(intx,inty)sum=x+y;main()inti,j;printf(”Pleaseenteriandj:”);scanf(”%d%d”,&i,&j);
12、plus(i,j);printf(”ni+j=%d”,sum);#include”stdio.h”int x=1,y=2;main()int m,n;int caculate(int,int);scanf(“%d,%d”,&m,&n);printf(“%d,%d”,x+y,caculate(m,n);printf(“%d,%d”,x+y,caculate(m,n);return(1);int caculate(int,int)static int x;x+=a+b;y+=a-b;return(x*y);输入:输入:4,2;输出:输出:5,24,7,723void类型函数类型函数voidvoid
13、 funcf(float a,float b)funcf(float a,float b)float f;float f;if(a0&b0)if(a0&b0)f=(a*b)/(a+b);f=(a*b)/(a+b);else if(a!=b)&(a0|b0)else if(a!=b)&(a0|by)z=x;elsez=y;return(z);main()externinta,b;printf(%d,max(a,b);inta=100,b=-200;可以多次可以多次在在函数内部说函数内部说明外部变量明外部变量外部变量定义外部变量定义在函数之外,只在函数之外,只能定义一次移到能定义一次移到最前,有何
14、不同最前,有何不同externextern删去删去有有何结果何结果?全局变量在程序的整个执行过程全局变量在程序的整个执行过程都占用内存都占用内存注注意意考虑程序的模块性、通用性、可考虑程序的模块性、通用性、可读性,应少用全局变量读性,应少用全局变量全局变量太多,当程序长且大时全局变量太多,当程序长且大时往往难以清楚的判断出各个瞬时往往难以清楚的判断出各个瞬时各个全局变量的值。各个全局变量的值。若函数中用到以前未定义过的参若函数中用到以前未定义过的参数,要用数,要用extern作外部变量说明作外部变量说明 由于由于CPU对寄存器的操作速度要远对寄存器的操作速度要远远快于对内存的操作,为了加快操作
15、速远快于对内存的操作,为了加快操作速度,可以使用寄存器型变量度,可以使用寄存器型变量6.2.3 register6.2.3 register型变量型变量 寄存器变量定义的一般形式为:寄存器变量定义的一般形式为:register数据类型标识符数据类型标识符变量名表;变量名表;静态静态变量变量6.2.4 6.2.4 静态变量静态变量 内部静态变量内部静态变量外部静态变量外部静态变量静态变量定义的一般形式为:静态变量定义的一般形式为:static数据类型标识符数据类型标识符变量名表;变量名表;函数内定义函数内定义在源文件的开在源文件的开始和所有函数始和所有函数之外定义之外定义static和全局变量若
16、不初始化和全局变量若不初始化,自动赋自动赋0static和全局变量初始化时必须用常量和全局变量初始化时必须用常量为其赋初值为其赋初值static型局部变量型局部变量的初始化仅执行的初始化仅执行一次一次若进入某程序块后若进入某程序块后auto和和register型变量要被初始化,则每次执行该程序型变量要被初始化,则每次执行该程序块都要进行初始化块都要进行初始化未初始化的未初始化的auto和和register变量,变量,其初值不定,不能直接在程序中使用其初值不定,不能直接在程序中使用extern型的变量不能进行初始化型的变量不能进行初始化几种不同存储类型变量的应用与比较几种不同存储类型变量的应用与
17、比较#defineABC“%d%d%d%dn”inti=1;main()staticinta;registerintb=-10;intc=0;voidother(void);printf(ABC,i,a,b,c);c=c+8;other();printf(ABC,i,a,b,c);i=i+10;other();i=1 a=0 b=-10 c=0i=1 a=0 b=-10 c=0i=33 a=4 b=0 c=15i=33 a=4 b=0 c=15i=33 a=0 b=-10 c=8i=33 a=0 b=-10 c=8i=75 a=6 b=4 c=15i=75 a=6 b=4 c=15voidot
18、her(void)staticinta=2;staticintb;intc=10;a=a+2;i=i+32;c=c+5;printf(ABC,i,a,b,c);b=a;【例】内部静态变量的作用域【例】内部静态变量的作用域#include“stdio.h”#defineABC“%d%d%d%dn”fun()inti,l;staticintj;registerintk;i=10;j=20;k=30;l=40;printf(ABC,i,j,k,l);main()inti,l;staticintj;registerintk;i=1;j=2;k=3;l=4;printf(ABC,i,j,k,l);fun
19、();printf(ABC,i,j,k,l);inta;staticintb;main()voidnext(void);a=30;b=100;printf(a:%db:%dn,a,b);next();printf(a:%db:%dn,a,b);voidnext(void)a=a+b;a=30b=100a=130b=100a为全局变量为全局变量b为静态变量为静态变量f(inta)autointb=0;staticintc=3;printf(%d%d,b,c);b=b+1;c=c+1;return(a+b+c);main()inta=2,i;for(i=0;i3;i+)printf(i=%d,f(
20、a)=%dn,i,f(a);i=0,f(a)=7,b=0,c=3i=1,f(a)=8,b=0,c=4i=2,f(a)=9,b=0,c=5比较比较auto和和static的不同的不同6.3 利用函数进行模块化程序设计利用函数进行模块化程序设计随着结构化程序设计方法的发展随着结构化程序设计方法的发展和广泛应用,模块化设计方法逐步成和广泛应用,模块化设计方法逐步成为结构化程序设计方法的为结构化程序设计方法的主体主体之一。之一。6.3.1模块化程序设计模块化程序设计模块化模块化设计设计方法:程序的编写不是开始就方法:程序的编写不是开始就逐条录入计算机语句和指令,而是首先用逐条录入计算机语句和指令,而是
21、首先用主程序、子程序、子过程等框架把软件的主程序、子程序、子过程等框架把软件的主要结构和流程描述出来,并定义和调试主要结构和流程描述出来,并定义和调试好各个框架之间的输入、输出链接关系。好各个框架之间的输入、输出链接关系。结构化结构化程序设计程序设计方法:主要观点是采用自方法:主要观点是采用自顶向下、逐步求精的程序设计方法;使用顶向下、逐步求精的程序设计方法;使用三种基本控制结构构造程序,任何程序都三种基本控制结构构造程序,任何程序都可由顺序、选择、重复三种基本控制结构可由顺序、选择、重复三种基本控制结构构造构造。其中每个模块用结构化程序设计的方法解其中每个模块用结构化程序设计的方法解决每个子
22、问题。决每个子问题。从键盘上输入五个字符从键盘上输入五个字符串,并对他们按从小到串,并对他们按从小到大的顺序进行排序。大的顺序进行排序。f()输入五个输入五个字符字符f1()排序排序f2()Scanf();Gets();Getchar();Strcmp();Strcpy();“黑盒子黑盒子”【例】给定两整数【例】给定两整数M M和和N N,求最大公约数,求最大公约数 根据欧几里德的转展相除法,应先根据欧几里德的转展相除法,应先求出求出M M和和N N中的较大者,再用较小的数去中的较大者,再用较小的数去除较大的数;若能整除,则较小的数就除较大的数;若能整除,则较小的数就是它们的最大公约数;若不能
23、整除,则是它们的最大公约数;若不能整除,则将原较小数当作大数,余数当作较小数将原较小数当作大数,余数当作较小数再相除。相除后的新余数若为零,则上再相除。相除后的新余数若为零,则上次的余数即为最大公约数。否则,再重次的余数即为最大公约数。否则,再重复上述过程,直到余数为零为止。复上述过程,直到余数为零为止。原理:原理:如果两个数有最大公约数如果两个数有最大公约数A,那么这,那么这两个数,以及这两个数的差,还有大数除两个数,以及这两个数的差,还有大数除以小数的余数,必然都是以小数的余数,必然都是A的倍数。的倍数。所以当最后两个数刚好能整除时,较小的所以当最后两个数刚好能整除时,较小的数就是最大公约
24、数。数就是最大公约数。(1)转展相除法求最大公约数的函数转展相除法求最大公约数的函数#includestdio.hgcd(intm,intn)inttemp,k;while(n!=0)temp=m%n;m=n;n=temp;k=m;return(k);(2)调用调用gcd函数的主函数函数的主函数main()intm,n,j,temp;scanf(%d%d,&m,&n);if(mn)temp=m;m=n;n=temp;j=gcd(m,n);printf(gcdis:%dn,j);inta(intn)intd,c,b(int);d=b(c);6.3.2 递归的概念递归的概念定义:定义:在调用在调用
25、一个函数的过一个函数的过程中又直接或程中又直接或间接地调用了间接地调用了该函数本身该函数本身intb(intm)inte,i;e=a(i);要实现递归设计,首先要分析问题是否要实现递归设计,首先要分析问题是否具有递归处理过程,该递归过程是什么具有递归处理过程,该递归过程是什么递归程序的设计递归程序的设计 递归最大缺点是效率低,原因如下:递归最大缺点是效率低,原因如下:(1)递递归归函函数数会会带带来来大大量量的的重重复复计计算算,例例如如n!程程序序,每每一一次次递递归归函函数数调调用用都都会会带带来前面的重复计算,大大降低效率来前面的重复计算,大大降低效率(2)函数的每一次调用都需进行保留现场、函数的每一次调用都需进行保留现场、传递参数以及恢复现场等操作,效率低传递参数以及恢复现场等操作,效率低【例】【例】用递归算法计算用递归算法计算0!+1!+n!#includestdio.hfloatfac(intn)floatf;if(n0)/结束递归的条件结束递归的条件!printf(n0,dataerror!);elseif(n=0|n=1)f=1;elsef=fac(n-1)*n;return(f);main()intn,i;floaty;scanf(%d,&n);for(i=0;i=n;i+)y=y+fac(i);printf(result=%f,y);