《模块化程序设计.ppt》由会员分享,可在线阅读,更多相关《模块化程序设计.ppt(69页珍藏版)》请在课桌文档上搜索。
1、2023/3/28,C语言程序设计,1,第三章 模块化程序设计,3.1 模块化程序设计思想3.2 函数的定义3.3 函数调用3.4 函数的原型与声明3.5 函数嵌套与递归,3.6 库函数的使用3.7 变量的作用域与存储类型3.8 指针与函数3.9 典型例题,2023/3/28,C语言程序设计,2,函数是C程序的基本单位,每一个函数模块用来实现一个特定的功能。,教学要求1理解函数的功能。2掌握函数定义的一般形式。3掌握函数的形参与实参的对应关系、参数传递方法及函数返回值的概念。4掌握函数调用的几种形式。5掌握函数嵌套调用的一般过程。6.掌握指针的定义、使用以及指针作为函数的参数。7.掌握返回指针
2、值的函数。8掌握局部变量与全局变量的概念及它们的使用特点。,函数:main(),getchar(),putchar(),printf(),scanf(),exp(),fabs(),sqrt(),gets(),puts(),strcpy(),strcmp(),strcat(),strupr(),strlwr(),strlen()等。,3.1 模块化程序设计的思想,例:从键盘中输入两个数,分别求出这两个数的最小公倍数和最大公约数。,考虑:在主函数中完成数据x,y的输入和结果的输出;求解最小公倍数和求解最大公约数分别有两个自定义函数实现。,2023/3/28,C语言程序设计,4,int gys(in
3、t x,int y),int gbs(int x,int y),#include void main()int a,b,m,n;printf(“input 2 numbers:n”);scanf(“%d,%d”,2023/3/28,C语言程序设计,5,结构化程序设计方法:自上向下、逐步分解、分而治之,必须有且只能有一个名为main的主函数C程序的执行总是从main函数开始,在main中结束函数不能嵌套定义,可以嵌套调用,2023/3/28,C语言程序设计,6,模块化程序设计的特点:(1)模块相对独立,功能单一。编写相对简单,可以独立编写调试。(2)可集体开发,缩短开发周期。不同的模块可以由不同
4、的人员开发,最终能够合成完整的程序。(3)开发出的模块,可在不同的应用程序中多次使用,减少重复劳动,提高开发效率。(4)测试、更新以模块为单位进行而不会影响其他模块。,函数分类从用户角度标准函数(库函数):由系统提供用户自定义函数从函数形式无参函数有参函数,使用库函数(见教材附录D)应注意:1、函数功能2、函数参数的数目和顺序,及各参数意义和类型3、函数返回值意义和类型4、需要使用的包含文件,3.2 函数的定义,2023/3/28,C语言程序设计,8,1、函数定义的一般形式:函数名(),当前函数返回主调函数的数据类型(即函数运行结果的数据类型),编写方法与主函数的编写方法一样,2023/3/2
5、8,C语言程序设计,9,例3.1:计算整数x的y次方long power(int x,int y)int n;long p=1;for(n=1;n=y;n+)p=p*x;return(p);,函数类型,参数列表,返回值,void main()int a,b;long c;scanf(“%d%d”,2023/3/28,C语言程序设计,10,定义形式:void 函数名()说明语句;语句;,例3.2 void print1()printf(“Welcome to China!n”);main()print1();print1();print1();,无返回值函数的调用,函数可以无参数,2、无参函数,
6、2023/3/28,C语言程序设计,11,3.3 函数调用3.3.1 函数调用的形式,函数语句:例 printstar();printf(“Hello,World!n”);函数表达式:例 m=max(a,b)*2;函数参数:例 printf(“%d”,max(a,b);m=max(a,max(b,c);,2023/3/28,C语言程序设计,12,例3.3:用函数实现两个数的数值交换,#include void swap(int a,int b)int t;t=a;a=b;b=t;printf(“result:x=%d y=%dn”,a,b);,void main()int x=10,y=5;p
7、rintf(“x=%d,y=%dn”,x,y);swap(x,y);,3.3.2 函数间的参数传递,2023/3/28,C语言程序设计,13,形参与实参形式参数:定义函数时函数名后面括号中的变量名实际参数:调用函数时函数名后面括号中的表达式,说明 实参必须有确定的值,可以是常量、变量、表达式、函数等;形参必须指定类型;形参与实参类型一致,个数相同;形参在函数被调用前不占内存;函数调用时为形参分配内存;调用结束,内存释放。,2023/3/28,C语言程序设计,14,参数传递方式值传递方式方式:函数调用时,为形参分配单元,并将实参的值复制到形参中;调用结束,形参单元被释放,实参单元仍保留并维持原值
8、特点:形参与实参占用不同的内存单元单向传递,实参的值传给形参,2023/3/28,C语言程序设计,15,例3.4 比较两个数并输出大者,#include void main()int a,b,c;scanf(%d,%d,2023/3/28,C语言程序设计,16,上节回顾,函数的组成部分?如何确定函数的数据类型?函数调用的方法有哪几种?简述参数的“值传递方式”?,函数名(),当前函数返回主调函数的数据类型(即函数运行结果的数据类型),函数语句:例 printstar();printf(“Hello,World!n”);函数表达式:例 m=max(a,b)*2;函数参数:例 printf(“%d”
9、,max(a,b);m=max(a,max(b,c);,函数调用时,为形参分配单元,并将实参的值复制到形参中;调用结束,形参单元被释放,实参单元仍保留并维持原值,例 3.5 计算x的立方,#include float cube(float x)return(x*x*x);void main()float a,product;printf(Please input value of a:);scanf(%f,x,1.2,1.2,1.728,2023/3/28,C语言程序设计,18,例3.6 从键盘中输入一个年份,判断该年是否是闰年。,#include void main()int year,st
10、;printf(“Input a year:n”);scanf(“%d”,int leap(int year)int st;if(year%4=0,函数调用,自定义函数,2023/3/28,C语言程序设计,19,5、函数定义的一般形式:函数名(),当前函数返回主调函数的数据类型(即函数运行结果的数据类型),编写方法与主函数的编写方法一样,6、函数声明的一般格式函数类型 函数名(形参类型 形参名,.),2023/3/28,C语言程序设计,20,3.3.3 函数的返回值,形式:return(表达式);或 return 表达式;或 return;功能:使程序控制从被调用函数返回到调用函数中,同时把返
11、值带给调用函数说明:函数中可有多个return语句,一旦遇到一个return语句,就立即返回到主调函数。若无return语句,遇时,自动返回调用函数若函数类型与return语句中表达式值的类型不一致,按前者为准,自动转换-函数调用转换void型函数,int max(int x,int y)if(xy)return(x);return(y);void main()int a,b,c;scanf(“%d,%d”,2023/3/28,C语言程序设计,21,例3.7 函数返回值类型转换,#include int max(float x,float y)float z;z=xy?x:y;return(z
12、);void main()float a,b;int c;scanf(%f,%f,输入:23.0,66.0输出:66,2023/3/28,C语言程序设计,22,例3.8:从键盘中输入两个数,分别求出这两个数的最小公倍数和最大公约数。,int gys(int x,int y),int gbs(int x,int y),return(x*y/gys(x,y);,int s;s=x*y/gys(x,y);return(s);,int t,s;if(xy)t=x;x=y;y=t;while(s=y%x)!=0)y=x;x=s;return(x);,函数嵌套调用,2023/3/28,C语言程序设计,23
13、,一、一般形式:函数类型 函数名(形参类型 形参名,.)作用:告诉编译系统函数类型、参数个数及类型,以便检验,3.4 函数的原型与声明,函数声明中,由于编译系统不检查参数名,所以可以只写形参的数据类型,而不写形参名,2023/3/28,C语言程序设计,24,二、说明1、函数定义与函数声明不同。2、函数声明位置:程序的数据说明部分,(1)在主调函数中;(2)在所有函数的外部(推荐使用)。3、下列情况下,可不作函数声明(1)若函数返值是char或int型,系统自动按int型处理(2)被调用函数定义出现在主调函数之前 有些系统(如Borland C+)要求函数声明指出函数返值类型和形参类型,并且对v
14、oid 和 int 型函数也要进行函数声明,2023/3/28,C语言程序设计,25,例3.9 函数声明举例,2023/3/28,C语言程序设计,26,3.5 函数嵌套与递归,一、函数的嵌套调用C规定:函数定义不可嵌套,但可以嵌套调用函数,例 3.10 求三个数中最大数和最小数的差值,#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,int dif(int x,int y,int z)retur
15、n 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);,二、拓扑算法递归,定义:函数直接或间接的调用自身叫函数的递归调用,int f(int x)int y,z;z=f(y);.return(2*z);,2023/3/28,C语言程序设计,29,例 3.11_1求n的阶乘(采用非递归算法),#include int fac(int n)int f,i;f=1;for(i=1;i=
16、n;i+)f=f*i;return(f);void main()int n,y;printf(Input a integer number:);scanf(%d,2023/3/28,C语言程序设计,30,分析一般来说,将n!描述成为:n!=1*2*3.*(n-1)*n但是,只要稍稍变换一下,就可以将其描述成为:n!=n*(n-1).3*2*1=n*(n-1)!这样,一个整数的阶乘就被描述成为一个规模较小的阶乘与一个数的积。同样,可以将(n-1)!描述成(n-1)*(n-2)!。依次类推。于是,一个问题就被描述成了一个较小规模的同样类型的问题了。,用递归的方法求n!,递归的终止条件,递归方式,4
17、!=4*(4-1)!,返回值6,返回值2,返回值1,3!=3*(3-1)!,2!=2*(2-1)!,1!=1,主调函数,返回值24,2023/3/28,C语言程序设计,32,例3.11_2 求n的阶乘(采用递归算法),#include int fac(int n)int f;if(n0)printf(n0,data error!);else if(n=0|n=1)f=1;else f=fac(n-1)*n;return(f);main()int n,y;printf(Input a integer number:);scanf(%d,2023/3/28,C语言程序设计,33,main函数,输入
18、m,y=fac(m),输出y,调用facmn,因 3!=0,1f=3*fac(3-1),返回f,调用facmn,返回f,返回f,因 2!=0,1f=2*fac(2-1),调用facmn,因1=1 f=1,结束,递归调用过程:,2023/3/28,C语言程序设计,34,main()fac(3)fac(2)fac(1)fac(3)*4 fac(2)*3 fac(1)*2 6 2 1,结果:24,2023/3/28,C语言程序设计,35,3.6 库函数的使用(自学),使用库函数应注意:1、函数功能2、函数参数的数目和顺序,及各参数意义和类型3、函数返回值意义和类型4、需要使用的包含文件,见教材例附录
19、A,2023/3/28,C语言程序设计,36,上节回顾,1、函数嵌套调用:,main(),调用函数a,结束,a函数,b函数,调用函数b,函数b()函数a()函数b;main()函数a;,#include int fac(int n)int f;if(n1)f=-1;else if(n=1|n=2)f=1;else f=fac(n-2)+fac(n-1);return(f);void main()int n,y;printf(Input a integer number:);scanf(%d,2、函数递归调用:,int fac(int n)int f,f1=1,f2=1,i;if(n1)f=-1
20、;else if(n=1|n=2)f=1;else for(i=3;i=n;i+)f=f1+f2;f1=f2;f2=f;return f;,2023/3/28,C语言程序设计,38,3.7 变量的作用域与存储类型3.7.1变量的作用域,所谓变量的作用域是指该变量有效的区域。按照变量的作用域,将C语言的变量分为局部变量和全局变量。一、局部变量-内部变量 位于一对花括号之间的所有语句称为一个代码块(也称为复合语句)。定义:出现在代码块开始位置的变量。说明:局部变量的作用域仅限于定义它的代码块内main中定义的变量只在main中有效不同函数中同名变量,占不同内存单元形参属于局部变量可定义在复合语句中
21、,且只在该复合语句中有效的变量,2023/3/28,C语言程序设计,39,运行结果:main:a=3,b=4sub:a=6,b=7main:a=3,b=4,2023/3/28,C语言程序设计,40,运行结果:4 3 2 1temp=0,2023/3/28,C语言程序设计,41,定义:任何在所有代码块之外定义的变量。有效范围:从定义变量的位置开始到本源文件结束,应尽量少使用全局变量,因为:全局变量在程序全部执行过程中占用存储单元降低了函数的通用性、可靠性,可移植性降低程序清晰性,容易出错,注意:若全局变量与局部变量同名,则全局变量被屏蔽!,二、全局变量-外部变量,说明:全局变量的作用是增强函数之
22、间联系的渠道为便于区分全局与局部变量,将全局变量名的第一个字母大写,2023/3/28,C语言程序设计,42,3、局部变量和全局变量,main中定义的变量只在main中有效不同函数中同名变量,占不同内存单元形参属于局部变量可定义在复合语句中,且只在该复合语句中有效的变量,2023/3/28,C语言程序设计,43,#include float Max=0,Min=100;float average(int n)int i;float s,aver1,sum=0;for(i=1;iMax)Max=s;else if(sMin)Min=s;sum+=s;return(sum/n);void main
23、()int n;float aver2;scanf(“%d”,例3.14,2023/3/28,C语言程序设计,44,例3.15 全局变量定义与声明,#include int max(int x,int y)int z;z=xy?x:y;return(z);void main()printf(max=%d,max(a,b);int a=13,b=-8;,运行结果:max=13,#include int a=13,b=-8;int max()int z;z=ab?a:b;return(z);void main()printf(max=%d,max();,编译出错,2023/3/28,C语言程序设计
24、,45,#include int a=3,b=5;int max(int a,int b)int c;c=ab?a:b;return(c);void main()int a=8;printf(max=%d,max(a,b);,例 3.16 全局变量与局部变量重名时,运行结果:max=8,a,b为全局变量,a,b为局部变量,a为局部变量,2023/3/28,C语言程序设计,46,#include int i;void main()void prt();for(i=0;i5;i+)prt();void prt()for(i=0;i5;i+)printf(“*”);printf(“n”);,例3.1
25、7 全局变量副作用,运行结果:?,*,2023/3/28,C语言程序设计,47,3.7.2 变量的存储类型,变量的存储类型:存储变量值的内存类型。变量的存储类型决定变量何时创建、何时销毁及它的值将保持多久。分为:静态存储和动态存储两种类型,1、自动变量(auto变量)C语言中使用最广泛的一种类型。函数内凡是未加类型说明的变量均视为自动变量。,2023/3/28,C语言程序设计,48,例如:int x,y;等价于:auto int x,y;,说明:自动变量的作用域仅限于定义该变量的个体内。当程序执行到定义自动变量的代码块时,该自动变量才被创建,当程序的执行离开该代码块时,这些自动变量便自行销毁,
26、所以自动变量属于动态存储方式。函数的形式参数也是自动变量。,2023/3/28,C语言程序设计,49,2、寄存器变量(register变量)以前介绍的变量都存放在内存里。当一个变量频繁读写时,要反复访问内存,从而花费大量的存取时间。C语言提供另一种变量,即寄存器变量。存放在CPU中,使用时不访问内存,而直接从寄存器中读写。,2023/3/28,C语言程序设计,50,例如:register int x,y;,说明:寄存器变量属于动态存储方式,只有局部自动变量和形式参数才可以定义为寄存器变量。由于CPU中寄存器的个数是有限的,所以编译器可以忽略register关键字,当有太多的变量声明为regis
27、ter时,只有个别的变量会存储在寄存器中,其余的编译器会按普通自动变量处理。在变量的定义中,一般并不需要使用register关键字。,2023/3/28,C语言程序设计,51,3、静态static静态变量赋初值,只执行一次再次调用函数时保留上次函数调用结束时的值。,例如:编写一个函数实现值自增1。在主函数中循环调用三次该函数,并输出结果。,#include int add();void main()int i,result;for(i=1;i=3;i+)result=add();printf(%d,result);int add()auto int num=5;/自动局部变量num+;retu
28、rn num;,#include int add();void main()int i,result;for(i=1;i=3;i+)result=add();printf(%d,result);int add()static int num=5;/*静态局部变量*/num+;return num;,结果:6 6 6,结果:6 7 8,2023/3/28,C语言程序设计,52,说明:静态局部变量在函数内定义,始终占用内存空间,直到整个源程序退出时才释放。静态局部变量仅赋一次初值。静态局部变量虽然在整个源程序都存在,但是其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后,
29、尽管该变量还继续存在,但不能使用它。静态局部变量若在声明时未赋初值,则系统自动初始化为0(对数值型变量)或0(对字符变量)。,2023/3/28,C语言程序设计,53,如果一个文件中的全局变量不允许其他文件的函数引用,则该变量要用static声明。或者说一个文件中的静态全局变量不允许其它文件中的函数引用。如果一个函数前用static声明,则这个函数不能被其他文件中的函数调用,称为内部函数或静态函数。,2023/3/28,C语言程序设计,54,4、外部声明extern外部变量是在函数的外部定义的全局变量。(1)如果想在定义之前的函数中引用全局变量,则在函数中用关键字extern声明。,#incl
30、ude void main()extern int a,b;printf(”%d”,max(a,b);int a=13,b=-8;,a,b的作用域扩展到整个main函数,(2)、如果一个C程序有多个源程序文件组成,则一个文件定义了全局变量,则另一个文件如果要引用它的全局变量,就要用extern作声明;,2023/3/28,C语言程序设计,56,(3)、如果一个函数前用extern声明,则这个函数可以被其他文件中的函数调用,称为外部函数。,2023/3/28,C语言程序设计,57,3.8 指针与函数3.8.1指针作为函数参数,值传递地址传递,指针变量就是存放变量地址的变量。变量的指针就是变量的地
31、址。,举例:int*p1,*p2,a;float*p3,b;,例3.3void swap(int a,int b)int t;t=a;a=b;b=t;printf(result:x=%d y=%dn,a,b);void main()int x=10,y=5;printf(x=%d,y=%dn,x,y);swap(x,y);,2023/3/28,C语言程序设计,58,指针变量作为函数的参数:,类型名 函数名(类型名*形式参数1,类型名*形式参数2,)说明部分;语句;,说明 参数的传递是值传递,单向的(从实参到形参)。那么如何理解通过指针作为参数可以改变主调函数中变量的值呢?形参得到实参的值即一个
32、地址,函数中可以通过形参引用该地址,从而可以改变该地址对应变量的值。,2023/3/28,C语言程序设计,59,#include main()int x=7,y=11;printf(x=%d,ty=%dn,x,y);printf(swapped:n);swap(x,y);printf(x=%d,ty=%dn,x,y);swap(int a,int b)int temp;temp=a;a=b;b=temp;,例3.18,2023/3/28,C语言程序设计,60,例3.18交换两个数的值,#include main()int x=7,y=11;printf(“Swapped:n);swap(x,y
33、);printf(x=%d,y=%dn,x,y);swap(int a,int b)int temp;temp=a;a=b;b=temp;,输出:,Swapped:x=7,y=11,#includevoid swap(int*px,int*py)int temp;temp=*px;*px=*py;*py=temp;main()int x=7,y=11,*p1,*p2;p1=,Swapped:x=11,y=7,例3.19 求三个数中的最大值和平均值用函数实现:,void mav(int a,int b,int c,int*p1,float*p2)*p1=a;if(*p1b)*p1=b;if(*p
34、1c)*p1=c;*p2=(a+b+c)/3.0;Return;main()int a,b,c,max,*p1;float ave,*p2;scanf(“%d%d%d”,Printf(“max=%d,ave=%f”,max,ave);,主函数的变量:,12,5,7,子函数的变量:,&ave,&max,7,5,12,&ave,&max,a,c,b,a,p2,p1,c,b,p2,p1,ave,max,12,8.0,举例,2023/3/28,C语言程序设计,62,上节回顾,(1)指针变量(2)变量的指针(3)int a=4,*s;s=则,*s=?(4)值传递方式 vs 地址传递方式,就是存放变量地址
35、的变量。,就是变量的地址。,4,#includevoid swap(int*px,int*py)int temp;temp=*px;*px=*py;*py=temp;main()int x=7,y=11,*p1,*p2;p1=,2023/3/28,C语言程序设计,63,3.8.2 返回指针值的函数(自学),一般定义形式为:类型名*函数名(类型名*形式参数1,*类型名*形式参数2)例如:int*a(int x,int y);a是函数名,调用它以后能得到一个指向整型数据的指针(地址),x、y 是函数的形参,为整型。,返回指针值的函数:一个函数可以带回一个整数值、字符值等,也可以带回指针型的数据,即
36、地址。,2023/3/28,C语言程序设计,64,例3.12编写一个函数求某班级学生成绩的最高分、最低分和平均分,void func(int n,float*aver,float*max,float*min)int i;float s;for(i=1;i*max)*max=s;if(s*min)*min=s;*aver+=s;*aver/=n;,main()int n;float x=0;y=100;aver1=0;printf(“how many students:n”);scanf(“%d”,2023/3/28,C语言程序设计,65,float*func(int n,float*max,f
37、loat*min)int i;float s,*aver,sum=0;static float aver1;aver=,main()int n;float x=0;y=100;*p;printf(“how many students:n”);scanf(“%d”,比较,2023/3/28,C语言程序设计,66,3.8.3 函数的指针(自学),1、函数的指针:函数的入口地址 在程序执行过程中调用函数时,计算机会转去执行函数体内的语句,因此计算机必须知道函数在什么地方。实际上函数在内存中也要占据一片存储单元,这片存储单元的起始地址,我们称其为函数的入口地址,即函数的指针,这个函数的入口地址是用函数
38、名来表示。因此我们可以定义一个指针变量,让它的值等于函数的入口地址,然后可以通过这个指针变量来调用函数,该指针变量称为指向函数的指针变量,2023/3/28,C语言程序设计,67,2、定义格式:数据类型(*指针变量名)(形参表列);例:int(*pt)(int a,int n);说明:数据类型:指针变量所指向的函数的返回值类型 形参表列:即指针变量所指向的函数的形参表列 格式中的小括号不能省略,3、应用(1)让指针变量指向函数 pt=add;因为函数名为函数的入口地址,所以直接将函数名 赋给指针变量即可(2)使用指针变量调用函数 格式:(*指针变量名)(实参表列),例:设计一个函数proces
39、s,在主函数中输入a,b两个数,第一次调用process时返回a,b中的最大数,第二次调用process时返回a,b中的最小数,第三次调用时返回二者的和。,int max(int a,int b)int c;c=ab?a:b;return(c);int min(int a,int b)int c;c=ab?a:b;return(c);int add(int a,int b)int c;c=a+b;return(c);,int process(int a,int b,int(*fun)(int,int)int result;result=(*fun)(a,b);return(result);main()int x,y,m,n,l;scanf(“%d,%d”,2023/3/28,C语言程序设计,69,3.9 典型例题,图书借阅系统,void input(struct book b),Void output(struct book b),void borrow(struct book b,char name),void back(struct book b,char*name),教材上例题自学,课余时间完成每章课后练习题。,