《C语言程序设计课程课件之第三章模块化程序设计.ppt》由会员分享,可在线阅读,更多相关《C语言程序设计课程课件之第三章模块化程序设计.ppt(71页珍藏版)》请在课桌文档上搜索。
1、第 三 章,模块化程序设计,引出,如果程序中有多个数,多处需要判断是否是素数,怎么办?反复书写那段重复的代码?解决办法:将判断素数的功能用一个独立的模块来实现,即自定义函数;在main函数中反复调用此功能模块就可以了。,for(i=2;i=x/2)printf(yesn);else printf(non);,main()int a,b;printf(input a number:);scanf(%d%d,模块化的优点:实现了代码的复用;编程效率高;代码少;功能分解,易于实现;便于合作开发大型项目等。,void sushu(int x)int i;for(i=2;i=x/2)printf(yes
2、n);else printf(non);,教学要求,1掌握函数定义的一般形式。2掌握函数调用的两种方式。3理解函数形参与实参的对应关系、参数传递方法及函数返回值的概念。4掌握指针的含义。5掌握指针作为函数参数的数据传递特点。,3.2 函数的定义,函数的定义位置:应写在其它函数的外面,前后都可以,但不能写在内部。函数的定义形式:第一行写函数名和括号 第二行开始是函数体,用大括号扩起来,如:,函数名称用户自定,函数定义的基本知识,函数定义的声明:函数被调用在前面,而函数定义书写在后面的,需要在使用该函数前进行声明。函数声明的形式:将函数定义的第一行信息重新写一遍,末尾加分号。,void sushu
3、(int x);main()sushu(a);void sushu(int x),声明可以放在调用之前的任意位置处。,main()float add(float x,float y);float a,b,c;scanf(%f,%f,float add(float a,float b);,float add(float,float);,函数声明的几种变通形式:,函数定义的高级知识,函数的参数函数的返回值,主调函数,自定义函数,参数,返回值,int sushu(int x),函数的形式分类1,有参函数无参函数,函数的形式分类2,有返回值函数无返回值函数,无论有参、无参,函数名后的括号不能省略。,无
4、参函数定义,通常也无返回值,仅需书写:void 函数名();例如:void clrscr();void draw()main()draw();draw();如果有返回值,则写明返回值类型,例如 char getchar();ch=getchar();,特点:空括号,有参函数定义,需写明参数的个数和类型:类型 函数名(类型 参数1,类型 参数2,)如:int sushu(int n);float fun(int m,int n);【强调】:形参定义时需分别写明它们的类型,类型相同不能只写一个,例如下错误:float fun(int m,n);,例如:求两个数的最大值的函数参数设计:max(),f
5、loat x,float y,float,函数定义分析练习,分析设计函数首部信息:实验4-1-4:float fun(int n)实验4-1-5:float fun(int m,int n)实验4-1-7:void fun(),有返回值函数定义,有返回值函数,在函数体内用return语句返回处理的结果值。如:int sushu(int x)int i;for(i=2;i=x/2;i+)if(x%i=0)return 0;return 1;return语句的两个功能:返回值、结束函数调用。,如果函数不返回值,则名称前写void,如:void draw(int x,int y)如果定义函数时名称前
6、没写明类型,默认为int类型,如:draw(int x,int y),【注意】:如果函数体内return语句返回值的类型与定义的函数名前类型不同,则以函数名前面的类型为准,系统会自动进行类型转换,可能会产生误差或错误。,?,函数定义练习,例:编写一个函数,其功能是求m的n次方,即mn。,分析:函数参数 函数返回值,2个,int类型参数返回值为float或double类型,函数首部信息如下:double fun(int m,int n),double fun(int m,int n)int i;double t=1;for(i=1;i=n;i+)t=t*m;return t;,main()int
7、 a,b;double c;printf(input two numbers:);scanf(%d%d,return(表达式);return 表达式;,形参在括号中定义后,直接在函数中使用,不能再次定义。,函数调用,形参和实参,形参:定义时括号内的参数叫做形式参数,简称形参。实参:调用是给予的实际数值叫做实际参数,简称实参。,形参和实参:个数相同、类型一致、一一对应。例如求m的n次方的函数:float fun(int m,int n)调用时如果求4的5次方,只能书写fun(4,5);不能写为fun(5,4);,有返回值函数调用,double fun(int m,int n)int i;doub
8、le t=1;for(i=1;i=n;i+)t=t*m;return t;,main()int a,b;double c;printf(input two numbers:);scanf(%d%d,赋 值,实参可以是常量、变量、表达式等。如:fun(2,8)fun(3,1+5),有返回值函数调用,输 出,double fun(int m,int n)int i;double t=1;for(i=1;i=n;i+)t=t*m;return t;,main()int a,b;printf(input two numbers:);scanf(%d%d,有返回值函数调用,double jiecheng
9、(int n)int i;double t=1;for(i=1;i=n;i+)t=t*i;return t;,main()int a,i;double b=0;scanf(%d,表达式运算,有返回值函数调用,b=jiecheng(a);b=b+jiecheng(i);printf(%.0lfn,jiecheng(a);,总结:将函数调用看做一个可以利用的值。函数调用一般不作为独立语句存在。jiecheng(a);,?,无返回值函数调用,编写一个函数,其功能画m行n列的矩形。,分析:函数参数 函数返回值,2个,int类型参数无返回值,为void,函数首部信息如下:void draw(int m,
10、int n),void draw(int m,int n)int i,j;for(i=1;i=m;i+)for(j=1;i=n;i+)printf(“*”);printf(“n”);,void main()int x,y;scanf(“%d%d”,总结:函数调用作为独立语句存在。,函数调用总结:两种形式:有返回值函数调用看做一个可以利用的值。无返回值函数调用作为独立语句存在。,本次课内容小节,函数定义的基本形式函数定义的参数表达函数定义的返回值类型函数调用的实参表达函数调用的2种形式,编程练习,编写一个函数,判断一个给定的数是否是水仙花数。编写一个函数,功能是输出如下三角形图案。,函数编程练习
11、,编写函数,求三角形面积。函数参数:三角形的三条边 函数返回值:三角形面积。,3-3,编程练习(实验题目),编写函数判断一个数是否是完数。完数:一个数如果恰好等于它的因子之和,这个数就是完数,例如6的因子为1、2、3,而61+2+3,因此6是完数。要求函数返回整型值。,3-4,3.7 库函数的使用,参考书后附录,P303注意包含相应的头文件。注意理解参数的类型和含义。,3.8局部变量与全局变量,局部变量-内部变量在函数内定义的变量是局部变量,其作用域:只在本函数内有效声明:不同函数中可定义的局部变量可同名,占不同内存单元形参属于局部变量在复合语句中也可以定义它的局部变量,其作用域是只在此复合语
12、句中有效。,i有效,全局变量-外部变量函数外部定义的变量称为全局变量其作用域为定义位置后的任何函数,int a=13,b=-8;int max()int z;z=ab?a:b;return(z);main()printf(“a=%d,b=%d,a,b);printf(max=%d,max();,例 全局变量举例,int max(int x,int y)int z;z=xy?x:y;return(z);main()printf(“a=%d,b=%d,a,b);printf(max=%d,max(a,b);int a=13,b=-8;,编译出错,因为全局变量的作用域为定义位置后的任何函数,全局变量
13、意味着多个函数可使用它,就是说各函数之间通过全局变量产生了相互的值的影响,因此降低了函数的独立性,使各函数间依赖型增强。应尽量少使用全局变量,int a=13,b=8;int sum()int z;z=a+b;a+;b-;return(z);main()printf(“a=%d,b=%d,a,b);printf(“sum=%d,sum();printf(“a=%d,b=%d,a,b);,输出结果为:a=13,b=8;sum=21;a=14,b=7;,int a=3,b=5;max(int a,int b)int c;c=ab?a:b;return(c);main()int a=8;printf
14、(max=%d,max(a,b);,例 全局变量与局部变量同名举例,int i;main()void prt();for(i=0;i5;i+)prt();void prt()for(i=0;i5;i+)printf(“%c”,*);printf(“n”);,例 全局变量副作用,运行结果:*,动态存储变量和静态存储变量,局部变量的存储类别:动态存储变量和静态存储变量。auto动态存储变量是在程序运行时根据需要动态分配存储空间。函数被调用时,分配给内存单元,调用结束后就释放内存单元。static静态存储变量局是指程序运行期间分配固定的存储空间。每次函数调用结束后不释放空间,只有在主程序运行结束才释
15、放内存单元。static静态变量在函数多次调用时,只赋一次初值,每次调用后保留当时的结果值。,变量的声明类型,局部变量的定义类型 auto自动类型 如:atuo int i,a,b;static静态类型 如:static int x,y;register 寄存器类型 如:register int i;补充:如无特殊声明,默认为auto类型,全局变量的定义类型 static 静态类型(默认是static类型)extern 外部类型 如:extern int s;补充:如无特殊声明,默认为static类型,int n=1;void func()static int a=2;int b=5;a+=2
16、;b+=5;n+=12;printf(a=%d,b=%d,n=%dn,a,b,n);main()int a=0,b=-10;printf(a=%d,b=%d,n=%dn,a,b,n);func();printf(a=%d,b=%d,n=%dn,a,b,n);func();,a=0,b=-10,n=1a=4,b=10,n=13a=0,b=-10,n=13a=6,b=10,n=25,3.9模块化程序设计指 针,普通函数参数值传递的特点,单向、值传递,函数return语句返回值的特点,只能返回一个值,void swap(int x,int y)int t;t=x;x=y;y=t;main()int
17、a,b;printf(input a number:);scanf(%d%d,输入4,3,输出after change:a=4,b=3,本例说明:自定义函数中修改了形参变量的值,反过来不会影响主调函数中实参的值。,问题的引入1、能不能在自定义函数中通过修改形参而改变主调函数中的变量值。2、如果想同时返回多个处理值给主调函数怎么办?,例题1:编写函数分别返回双精度实数的整数部分和小数部分。例题2:编写函数交换两个变量的值,并在主函数中输出结果。,解 决 方 案 使用指针类型的参数,void fun(int*x,int*y)int t;t=*x;*x=*y;*y=t;main()int a,b;p
18、rintf(input a,b:);scanf(%lf%d,1、定义指针参数,2、间接访问,3、传递地址,2、间接访问,int fun(double a,double*b)int x;x=(int)a;*b=a-x;return x;main()double x,y;int c;scanf(%lf,解 决 方 案 使用指针类型的参数,1、定义指针参数,3、传递地址,通过演示的例题说明:为什么有时需要在函数的参数中使用指针类型的参数?,1.可以同时将多个函数处理结果返回给主调函数。,2.可以间接访问主调函数的实参变量,即将函数内的值反向传递给实参变量。,本节内容,1 指针的概念,2 指针变量的定
19、义和引用,3 指针作为函数参数,指针概念,使用指针类型:目的是引用变量的内存地址,不通过变量的名称,而是直接通过内存地址对变量进行操作。,因为变量的作用域范围限制,有时是不能直接用变量名访问某些变量的,如下例:,牢记一个概念:指针就是变量的地址。,void swap()int t;t=a;a=b;b=t;main()int a,b;printf(input a number:);scanf(%d%d,变量a、b是函数main中的局部变量,不能在swap函数中使用。,此时,需要知道变量a,b的地址,通过地址间接访问a,b,不同类型的变量系统在编译时为其分配不同字节的存储空间,例如int类型,分配
20、4个字节的连续空间,float类型分配4个字节、double类型分配8个字节、char类型分配1个字节。所谓变量的地址就是这一连续内存空间的首地址编号。可使用“&”运算符取出变量的地址,例如:,变量的地址,main()int a;float b;double x;char c;printf(a address is%xn,指针变量是一个单独的变量,需要单独定义和赋值。它的里面存放的是另外一个变量的内存单元地址。,2 指针变量的定义和引用,定义形式:,基类型*指针变量名;,举例:,int*p;char*m;,指针p只能存放一个整型变量的地址,指针m只能存放char类型变量的地址。,定义形式:,基
21、类型*指针变量名;,举例:,int*p;float*m;,赋值:,int*p,a;p=,赋值后,指针p就指向了变量a,以后可以通过指针p实现对变量a的间接访。,指针变量只能赋地址值,p,a,5,&a,使用:,int*p,a;p=,通过地址间接访问变量a,此处相当于a6;,此处的*是间接访问符(或指向运算符)取存储单元的内容,注意与乘运算符不同。*只能作用于指针变量。,总结:指针定义:指针赋值:指针使用:等价式:*p a,int a,*p;p=/*直接访问形式*/,void fun(int*x,int*y)*x=*x+2;*y=*y+3;main()int a,b;printf(input a,
22、b:);scanf(%d%d,参数的定义参数在函数内的使用实参的形式,间接访问*x a*y b,11,实参a,函数调用,形参*x,传递地址&a,13,指针类型参数传递,*x=*x+2,指针类型的形参,本质上传递的是地址,因此值的传递是双向性的,既可由实参将值传入函数,也可在函数内部将值传回给实参。,指针参数总结,双向、地址传递,普通函数参数值传递的特点,单向、值传递,实验题目,编写函数,求两个数的最大公约数和最小公倍数。编写函数,求一个数的各位数字之和,并判断它是否是素数。编写函数计算银行存款需要多少年才能翻一番,假设银行存款年利率为1.9%,当时的金额是存款本金的多少倍?编写函数,将主调函数
23、中两个变量值分别乘2和除2。,补充赋值可以进行初始化,也可以使用赋值语句,但必须赋地址值。,(1)、初始化:int a,*s=,(2)、赋值语句 int a,*s;s=,注意:不能给指针变量赋一个整数值。,注意:只能用同类型变量的地址进行赋值!如定义:int*s;float f;则 s=&f;是非法的。,表示空指针,即不指向任何单元,在头文件stdio.h中定义。,int*s=,补充:指针变量可以进行的操作(1)赋值:int a,*p1=(只能和一个整数),是指拨一个变量的位置,并非地址值简单加1。,(4)取内容:*p1=5;a=5;printf(“%d”,*p1);(5)比较:一般与指针常量
24、NULL进行比较;两指针 变量值的大小比较无意义。,例1#include main()int a1=11,a2=22;int*p1,*p2;p1=,举例,p1,&a1,11,22,a1,p2,a2,&a2,*p1,*p2,&a1,运行结果如下:11,22 11,11,*p2,*p2,例2#include main()int a1=11,a2=22;int*p1,*p2,*p;p1=,p1,&a1,11,22,a1,p2,a2,&a2,&a1,&a2,举例,运行结果如下:11,22 22,11,*p1,*p2,*p2,*p1,例3#include main()int a1=11,a2=22,t;
25、int*p1,*p2;p1=,p1,&a1,11,22,a1,p2,a2,&a2,*p1,*p2,22,11,举例,运行结果如下:11,22 22,11,指针基础知识:指针变量赋地址值;间接访问;等价式:*p a,总结与复习,指针作为函数的参数1、定义形参变量为指针类型2、函数内部使用间接访问的形式使用形参变量3、函数调用时,对于指针位置的实参应为地址值。,指针参数,void fun(int*a,int*b)*a=*a+2;*b=*b+3;main()int a,b;printf(input a,b:);scanf(%d%d,3.5 函数的嵌套调用和函数声明,3.6 函数的递归调用,3.7 库函数的使用,略,3.11 函数的指针,