第06章函数与预处理.ppt

上传人:本田雅阁 文档编号:2250542 上传时间:2019-03-11 格式:PPT 页数:87 大小:418.51KB
返回 下载 相关 举报
第06章函数与预处理.ppt_第1页
第1页 / 共87页
第06章函数与预处理.ppt_第2页
第2页 / 共87页
第06章函数与预处理.ppt_第3页
第3页 / 共87页
亲,该文档总共87页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第06章函数与预处理.ppt》由会员分享,可在线阅读,更多相关《第06章函数与预处理.ppt(87页珍藏版)》请在三一文库上搜索。

1、第6章 函数与预处理,*重点与难点 6.1 模块化软件与C程序的模块结构 6.2 函数定义、参数和返回值 6.3 函数调用 6.4 函数中使用的变量,6.5 内部函数与外部函数 6.6 多文件的程序运行 6.7 预处理命令 *本章小结 *作业,重点与难点,重点:函数的定义、声明、参数传递和调用;函数的嵌套调用;变量的作用域与生存期。 难点:参数传递和函数的嵌套调用。,6.1 模块化软件与C程序的模块结构,6.1.1 模块化软件 6.1.2 C语言的模块结构,6.1.1 模块化软件,模块化:就是将一个较为复杂的、大型的项目按其功能与结构,划分为若干个功能相对独立的模块(Module),每个模块实

2、现一个功能。 C语言:是一种结构化程序设计语言,结构化程序设计的基本思想之一就是程序的“模块化”。每个模块在C语言中可以用函数来实现。,6.1.2 C语言的模块结构,C程序的组成,C程序:可以由一个或多个C源程序文件组成。在C语言中,一个C语言的源程序文件就是一个编译单位。 函数:它是C源程序的基本模块。,函数分类,从用户使用的角度 标准库函数与用户自定义函数 从有无函数返回值的角度 有返回值函数与无返回值函数 从有无参数的角度 有参函数与无参函数,6.2 函数定义、参数和返回值,6.2.1 函数定义的一般形式 6.2.2 函数参数与参数传递 6.2.3 函数返回值,6.2.1 函数定义的一般

3、形式,1、无参函数 2、有参函数 3、空函数,1、无参函数,类型标识符 函数名() 类型说明 语句 ,void printmessage() printf(“nHello!“); ,2、有参函数,类型标识符 函数名(形式参数列表) 类型说明 语句 ,int max(int x,int y) return (xy?x:y);,3、空函数,类型说明符 函数名() ,调用这种函数没有任何实际作用,但 在系统规划的初期用于标示各个部分, 使得程序结构清楚,可读性好,以后 扩充新的功能方便。,6.2.2 函数参数与参数传递,1、分类:形式参数和实际参数。 2、形参:在函数定义的时候声明的参数称为形式参数

4、,简称形参。形参是变量名。 3、实参:在函数调用的时候使用到的参数称为实际参数,简称实参。实参是表达式。,参数传递,1、参数传递是实参传递给形参。 2、传递要求:在参数传递的过程中,实参的个数必须与形参的个数一样多,并且类型应相同或保持兼容,否则系统会给出错误。 3、分类 值传递与地址传递,值传递方式,一般采用的是单向的值传递,即将实参的值拷贝给形参。形参在调用前和调用后都是不存在的,只有函数被调用时形参才被分配相应的存储单元。实参与形参即使是同名的变量,它们也代表不同的存储单元,互不影响。,值传递图示,c=min(a,b);,函数调用开始,函数调用结束,地址传递方式,如果形参是地址方式,实参

5、传递给形参采用地址传递方式,即形参共用实参的地址,这样,形参的改变也会间接地改变形参的值。,6.2.3 函数返回值,函数的返回值是通过return语句返回主调函数。该语句的形式如下:,return 表达式;,一个函数至多只能返回一个值。,返回值类型,return语句的表达式的计算结果的类型常常与函数定义的返回类型不一致。这时应该以哪一个为准呢? (1)C语言规定,函数的返回值的类型以函数定义的类型为准。 (2)如果return语句中的表达式是数值型的,系统自动进行类型转换。如果系统不能自动转换的,则需要编程人员进行强制转换。,函数默认类型,如果在函数定义时没有指定返回值的类型,系统默认为int

6、型的。,无return语句,如果被调用函数中没有return语句,是不是没有返回值呢? 其实不是,函数仍然返回一个值,只不过这个值是不确定的、也不是用户所希望得到的。 如果一个函数没有返回值,最好是用void明确地表示出来。这样,可以保证函数正确调用,减少出错。,6.3 函数调用,6.3.1 函数的一般调用 6.3.2 函数的嵌套调用 6.3.3 函数的递归调用,6.3.1 函数的一般调用,函数名(实参表列),函数调用形式,(1)函数语句 printf(“Welcome to C language.“); (2)函数表达式 c=max(a,b); (3)函数作参数 d=max(a,max(b,

7、c) ;,6.3.2 函数的嵌套调用,举例:用弦截法求方程的根。,自定义函数,1、f(x) = 2、xpoint( , )= 3、root(x1,x2),函数调用关系,root函数,float root(float x1,float x2) float x,y,y1=f(x1); do x=point(x1,x2); y=f(x); if(y*y10) y1=y;x1=x; else x2=x; while(fabs(y)=0.0001); return(x); ,6.3.3 函数的递归调用,1)直接调用自身,2)间接调用自身,递归的两个阶段,回推和递推 回推到可以确定值(即递归结束条件)时结

8、束;递推从起初值开始进行迭代。,4!的回推与递推举例,回推 f(4)=4*f(3)=4*3*f(2)=4*3*2*f(1) 递推 f(1)=1 f(2)=2*f(1)=2 f(3)=3*f(2)=3*2=6 f(4)=4*f(3)=4*6=24,递归调用实质,在不能计算出结果时,先压栈;在能够计算时,逐个出栈。,例6.8 利用递归算法求Fibonacci数列,0 (n=0) f(n)= 1 (n=1) f(n-1)+f(n-2) (n1),long f(int n) long c; if(n=0) c=0; else if(n=1) c=1; else c=f(n-1)+f(n-2); ret

9、urn(c); ,课堂训练,自定义两个函数实现: (1)判断一个整数是否为完数; (2)在屏幕上显示完数的因子。 要求:在main函数中输入整数,并调用上述两个函数进行测试。,6.4 函数中使用的变量,6.4.1 局部变量与全局变量 6.4.2 变量的存储方式 6.4.3 变量的存储类别,6.4.1 局部变量与全局变量,1、局部变量 2、全局变量,1、局部变量,在一个函数内部定义的变量是内部变量,也称局部变量。 局部变量只在定义它的函数范围内有效(即可以使用),在其他函数不能使用。,局部变量举例,float f1(int a) int b,c; . char f2(int x,int y) i

10、nt i,j; main() int a,b; . int c; c=a+b; ,a,b,c有效,x,y,i,j有效,c有效,a,b有效,2、全局变量,程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量;而在函数外定义的变量是外部变量,也称全局变量。 全局变量的有效范围:从定义变量的位置开始到本源文件结束。,全局变量举例,int p=1,q=5; float f1(a) int b,c;. char a,b; char f2(int x,int y) int i,j; main() int a,b; char c; c=a+b; ,a,b,c有效,x,

11、y,i,j有效,c有效,a,b有效,全局变量 a,b有效,全局变量 p,q有效,例6.9 全局变量a,int a=10; fun(int i) a+=2*i; return a; main() int a=10; printf(“n%d,%d“,fun(a),a); printf(“n%d,%d“,fun(a),a); ,运行结果: 20,10 40,10,例6.10 有一个数组存放10个学生的成绩,编一个函数求出10个学生的平均成绩、最高分和最低分。,float max=0,min=0; float averagescore(float a,int n) int i; float sum=a

12、0; max=min=a0; for(i=1;imax) max=ai; else if(aimin) min=ai; sum=sum+ai; return(sum/n); ,全局变量应慎用,全局变量在程序执行过程中一直占用内存。 降低了函数的通用性。 使用全局变量过多,会降低程序的可读性。 建议不在必要时不要使用全局变量。,6.4.2 变量的存储方式,静态存储方式,静态存储方式是指在程序运行期间分配固定的存储空间的方式。 全局变量和静态(static)变量全部存放在静态存储区。 静态存储方式在程序执行过程中一直占据固定的存储单元,直到程序执行完毕才释放。,动态存储方式,动态存储方式:是在程序

13、运行期间根据需要进行动态分配存储空间的方式。 在动态存储区存放如下数据:形参、非静态变量、堆栈(函数调用时的现场保护和返回地址)。 动态存储方式根据函数调用的需要,动态地分配和释放存储空间。,6.4.3 变量的存储类别,在C语言中,每一个变量和函数有两个属性:数据类型和存储类别。 存储类别分四类,auto变量,auto int b,c=3; int b,c=3;,两者等价,static,f(int a) auto int b=0; static int c=3; b=b+1;c=c+1; return(a+b+c); main() int a=2,i; for(i=0;i3;i+) print

14、f(“%d “,f(a); ,运行结果:7 8 9,为何结果不是:7 7 7呢?,原因:static型变量是在编译时赋初值的,只赋值一次,即在程序运行时它已有初值。,举例 打印15的阶乘值,int fac(int n) static int f=1; f=f*n; return(f); main() int i; for(i=1;i=5;i+) printf(“n%d!=%d“,i,fac(i); ,运行结果 1!=1 2!=2 3!=6 4!=24 5!=120,慎用static变量,static变量长期占用内存,直到程序执行完才释放。 降低了程序的可读性。,register变量,寄存器的存

15、取时间比内存要快 C语言允许频繁使用的局部变量的值存放在cpu的寄存器中。 register int i; Turbo c将register变量作auto变量处理。,用extern声明外部变量,编译时,将外部变量(即全局变量)分配在静态存储区。如果外部变量定义处在后或在其他文件中并且使用在前时,则需要对它进行声明。声明分为: 1、在一个文件内声明外部变量 2、在多文件的程序中声明外部变量,声明与定义,定义:是定义性声明,需要建立存储空间。定义只能有一次。 声明:是引用性声明。声明可以出现多次。声明的作用是一个已在后面定义的外部变量,仅仅是为了“提前”引用该变量而作的“声明”。声明要求外部变量已

16、经定义。,例6.13 外部变量声明,main() extern x,y; int z; z=x*y; printf(nz=%d“,z); int x=2, y=3;,例6.14 在多文件的程序中声明外部变量,*eg0614a.c int a=4; int max(int x,int y) return(xy?x:y);,*eg0614b.c extern a; main() int x=2,y=3,z; z=x*a+a*y*max(x,y); printf(“nz=%d“,z); ,6.5 内部函数与外部函数,1、内部函数 2、外部函数,1、内部函数,如果一个函数只能被本文件中的其他函数调用,

17、而不能被其他文件中的函数调用, 这种函数称为内部函数(或称静态函数)。定义内部函数的一般形式是(函数头):,static 类型说明符 函数名(形参表),2、外部函数,若一个函数除了可以被本文件中的其他函数调用外,还可以被程序中的其他源文件的函数调用,这样的函数称为外部函数。它的定义一般形式:,extern 类型说明符 函数名(形参表),注意:extern可以省略,例6.15 内部函数与外部函数,*eg0615a.c extern int a; extern int max(int m,int n); static int z=12; static int min(int x,int y) re

18、turn(xy?x:y); main() int x=2,y=3; printf(“max=%d,min=%d“,max(x,y),min(a,z); ,*eg0615b.c int a=10; int max(int m,int n) if(m=n)return(m); else return(n); ,6.6 多文件的程序运行,1、工程方法 2、文件包含方法,1、工程方法,2、文件包含方法,在eg0615.c的开始添加一行: #include 在文件包含方式中,由于最终生成一个目标文件。所以关于变量、函数的声明都不必要了。,6.7 预处理命令,在前面章节已经使用了如下形式: #define

19、 PI 3.14 #include,预处理命令,ANSI C 标准规定可以在C源程序中加入一些“预处理命令”,以改进程序设计环境,提高编程效率。 预处理命令不是C语言本身的组成部分,必须在正式编译前进行处理。 C提供的预处理功能主要有一下3种:,1、宏定义 2、文件包含 3、条件编译,6.7.1 宏定义,1、不带参数的宏定义 2、带参数的宏定义,1、不带参数的宏定义,一般形式 #define 标识符 字符串 不带参数的宏常用来表示符号常量 举例 #define PI 3.1415926,宏定义的作用,宏定义是用宏名代替一个字符串,即只作简单的置换,不作正确性检查。也不分配存储空间。 举例 #d

20、efine PI 3.14; area=PI*r*r; 展开后如下: area=3.14;*r*r; /*error*/,宏定义的作用域,宏名的有效范围为定义命令之后到本源文件结束。 可以用#undef命令终止宏定义的作用域。,宏的作用域举例,#define G 9.8 main() #undef G f1() .,G的作用范围,宏的层层置换,#define R 3.0 #define PI 3.14 #define L 2*PI*R #define S PI*R*R main() printf(“nL=%fnS=%f“,L,S); ,9.1.2 带参数的宏定义,一般形式 #define 宏名

21、(参数表) 字符串,带参数宏举例(例6.17),#define PI 3.14 #define S(r) PI*r*r main() float a,area; a=3.6; area=S(a); printf(“nr=%f area=%f“,a,area); ,带参数宏与函数,形式相同,容易混淆 不同之处主要有: (1)函数调用需要参数检查;宏只作简单置换。 (2)函数调用在程序运行时处理,分配内存单元;宏展开在正式编译前进行,不分配存储单元,无返回值概念。 (3)函数调用占运行时间,源程序保持不变;宏展开只占编译时间,展开后源程序变长。,举例:可以得到多个结果的宏,#define PI 3

22、.14 #define CIRCLE(R,L,S) L=2*PI*R; S=PI*R*R; main() float r,l,s; printf(“nr=“); scanf(“%f“, ,6.7.2 “文件包含”处理,“文件包含”处理是指一个源文件可以将另外一个源文件的全部包含进来。 一般形式,#include“文件名“ 或 #include,两种包含形式比较,#include:系统到存放C库函数文件所在的目录中寻找要包含的文件,这种称为标准方式。 #include“file2.c“:系统先在用户当前目录中寻找要包含的文件,如果找不到,再按标准方式查找。,“文件包含”的含义,file1.c,#

23、include,file2.c,B,A,file1.c,A,B,“文件包含”的实质,被包含的文件与其所在的文件,在预编译后已经成为同一个文件(而不是两个文件)。 被包含的文件的外部变量作用域扩展到了包含文件,所以不必用extern声明。,6.7.3 条件编译,一般情况下,源程序中所有的行都参加编译。但如果对其中一部分内容只在满足一定条件才进行编译,这就是“条件编译”。,条件编译形式,1) #ifdef 标识符 程序段1 #else 程序段2 #endif 2)#ifdef 标识符 程序段1 #endif,3)#ifndef 标识符 程序段1 #else 程序段2 #endif 4)#if 表达

24、式 程序段1 #else 程序段2 #endif,例9.7 条件编译大小写转换,#define LETTER 1 main() char str20=“C language“,c; int i=0; while(c=stri)!=0) i+;,#if LETTER if(c=a ,程序调试输出,#define DEBUG 1 main() int i,s=0; while(i=100) s=s+i i+ #ifdef DEBUG printf(“ni=%d,s=%d“,i,s); #endif printf(“nsum=%d“,s); ,课堂训练,简单的学生成绩管理程序。要求编写下列函数: (1)输入函数:输入5个学生3门课程的成绩; (2)输出函数:在屏幕上按一行一个学生资料显示成绩。 (3)计算函数:计算课程的平均成绩。,本章小结,函数的定义; 函数参数的传递; 函数的嵌套调用、递归调用; 变量的作用域和生存期; 内部函数与外部函数; 多文件程序的运行。,作业,p119 6.28, 6.29, 6.32, 6.31,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1