《c程序设计授课》课件-第06章 函数与预处理_第1页
《c程序设计授课》课件-第06章 函数与预处理_第2页
《c程序设计授课》课件-第06章 函数与预处理_第3页
《c程序设计授课》课件-第06章 函数与预处理_第4页
《c程序设计授课》课件-第06章 函数与预处理_第5页
已阅读5页,还剩82页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章函数与预处理*重点与难点6.1模块化软件与C程序的模块结构6.2函数定义、参数和返回值6.3函数调用6.4函数中使用的变量6.5内部函数与外部函数6.6多文件的程序运行6.7预处理命令*本章小结*作业重点与难点重点:函数的定义、声明、参数传递和调用;函数的嵌套调用;变量的作用域与生存期。难点:参数传递和函数的嵌套调用。6.1模块化软件与C程序的模块结构6.1.1模块化软件6.1.2C语言的模块结构6.1.1模块化软件模块化:就是将一个较为复杂的、大型的项目按其功能与结构,划分为若干个功能相对独立的模块(Module),每个模块实现一个功能。C语言:是一种结构化程序设计语言,结构化程序设计的基本思想之一就是程序的“模块化”。每个模块在C语言中可以用函数来实现。6.1.2C语言的模块结构mainabcdefeghhiC程序的组成C程序:可以由一个或多个C源程序文件组成。在C语言中,一个C语言的源程序文件就是一个编译单位。函数:它是C源程序的基本模块。函数分类从用户使用的角度

标准库函数与用户自定义函数从有无函数返回值的角度

有返回值函数与无返回值函数从有无参数的角度

有参函数与无参函数6.2函数定义、参数和返回值6.2.1函数定义的一般形式6.2.2函数参数与参数传递6.2.3函数返回值6.2.1函数定义的一般形式1、无参函数2、有参函数3、空函数1、无参函数

类型标识符函数名(){

类型说明语句

}voidprintmessage(){printf("\nHello!");}2、有参函数

类型标识符函数名(形式参数列表)

{

类型说明语句

}intmax(intx,inty){return(x>y?x:y);}3、空函数

类型说明符函数名()

{}

调用这种函数没有任何实际作用,但在系统规划的初期用于标示各个部分,使得程序结构清楚,可读性好,以后扩充新的功能方便。6.2.2函数参数与参数传递1、分类:形式参数和实际参数。2、形参:在函数定义的时候声明的参数称为形式参数,简称形参。形参是变量名。3、实参:在函数调用的时候使用到的参数称为实际参数,简称实参。实参是表达式。参数传递1、参数传递是实参传递给形参。2、传递要求:在参数传递的过程中,实参的个数必须与形参的个数一样多,并且类型应相同或保持兼容,否则系统会给出错误。3、分类

值传递与地址传递值传递方式

一般采用的是单向的值传递,即将实参的值拷贝给形参。形参在调用前和调用后都是不存在的,只有函数被调用时形参才被分配相应的存储单元。实参与形参即使是同名的变量,它们也代表不同的存储单元,互不影响。值传递图示c=min(a,b);22ax33by函数调用开始28ax35by函数调用结束复制地址传递方式

如果形参是地址方式,实参传递给形参采用地址传递方式,即形参共用实参的地址,这样,形参的改变也会间接地改变形参的值。6.2.3函数返回值函数的返回值是通过return语句返回主调函数。该语句的形式如下:return表达式;一个函数至多只能返回一个值。返回值类型

return语句的表达式的计算结果的类型常常与函数定义的返回类型不一致。这时应该以哪一个为准呢?(1)C语言规定,函数的返回值的类型以函数定义的类型为准。(2)如果return语句中的表达式是数值型的,系统自动进行类型转换。如果系统不能自动转换的,则需要编程人员进行强制转换。函数默认类型

如果在函数定义时没有指定返回值的类型,系统默认为int型的。无return语句如果被调用函数中没有return语句,是不是没有返回值呢?

其实不是,函数仍然返回一个值,只不过这个值是不确定的、也不是用户所希望得到的。如果一个函数没有返回值,最好是用void明确地表示出来。这样,可以保证函数正确调用,减少出错。6.3函数调用6.3.1函数的一般调用6.3.2函数的嵌套调用6.3.3函数的递归调用6.3.1函数的一般调用函数名(实参表列)函数调用形式(1)函数语句

printf("WelcometoClanguage.");(2)函数表达式

c=max(a,b);(3)函数作参数

d=max(a,max(b,c));

6.3.2函数的嵌套调用main函数调用a函数结束①②⑨a函数③调用b函数⑦⑧④b函数⑤⑥举例:用弦截法求方程的根。

xy自定义函数1、f(x)=2、xpoint(,)=3、root(x1,x2)函数调用关系main函数root输出根x结束rootxpointxpointff函数root函数floatroot(floatx1,floatx2){floatx,y,y1=f(x1);do{x=point(x1,x2);y=f(x);if(y*y1>0){y1=y;x1=x;}elsex2=x;}while(fabs(y)>=0.0001);return(x);}6.3.3函数的递归调用f函数调用f函数1)直接调用自身f1函数调用f2函数f2函数调用f1函数2)间接调用自身递归的两个阶段回推和递推回推到可以确定值(即递归结束条件)时结束;递推从起初值开始进行迭代。

1(n=0,1)/*递归结束条件*/f(n)=n*f(n-1)(n>1)4!的回推与递推举例回推

f(4)=4*f(3)=4*3*f(2)=4*3*2*f(1)

递推

f(1)=1f(2)=2*f(1)=2f(3)=3*f(2)=3*2=6f(4)=4*f(3)=4*6=24递归调用实质在不能计算出结果时,先压栈;在能够计算时,逐个出栈。例6.8利用递归算法求Fibonacci数列

0(n=0)f(n)=1(n=1)f(n-1)+f(n-2)(n>1)longf(intn){longc;if(n==0)c=0;elseif(n==1)c=1;elsec=f(n-1)+f(n-2);return(c);}课堂训练自定义两个函数实现:(1)判断一个整数是否为完数;(2)在屏幕上显示完数的因子。要求:在main函数中输入整数,并调用上述两个函数进行测试。6.4函数中使用的变量6.4.1局部变量与全局变量6.4.2变量的存储方式6.4.3变量的存储类别6.4.1局部变量与全局变量1、局部变量2、全局变量1、局部变量在一个函数内部定义的变量是内部变量,也称局部变量。局部变量只在定义它的函数范围内有效(即可以使用),在其他函数不能使用。局部变量举例floatf1(inta){intb,c;...}charf2(intx,inty){inti,j;....}main(){inta,b;...{intc;c=a+b;}}a,b,c有效x,y,i,j有效c有效a,b有效2、全局变量程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量;而在函数外定义的变量是外部变量,也称全局变量。全局变量的有效范围:从定义变量的位置开始到本源文件结束。全局变量举例intp=1,q=5;floatf1(a){intb,c;...}chara,b;charf2(intx,inty){inti,j;....}main(){inta,b;......{charc;c=a+b;}....}a,b,c有效x,y,i,j有效c有效a,b有效全局变量a,b有效全局变量p,q有效例6.9全局变量ainta=10;fun(inti){a+=2*i;returna;}main(){inta=10;printf("\n%d,%d",fun(a),a);printf("\n%d,%d",fun(a),a);}运行结果:20,1040,10例6.10有一个数组存放10个学生的成绩,编一个函数求出10个学生的平均成绩、最高分和最低分。floatmax=0,min=0;floataveragescore(floata[],intn){inti;floatsum=a[0];max=min=a[0];for(i=1;i<n;i++)if(a[i]>max)max=a[i];elseif(a[i]<min)min=a[i];sum=sum+a[i];return(sum/n);}地址传递全局变量应慎用全局变量在程序执行过程中一直占用内存。降低了函数的通用性。使用全局变量过多,会降低程序的可读性。建议不在必要时不要使用全局变量。6.4.2变量的存储方式用户区程序区静态存储区动态存储区静态存储方式静态存储方式是指在程序运行期间分配固定的存储空间的方式。全局变量和静态(static)变量全部存放在静态存储区。静态存储方式在程序执行过程中一直占据固定的存储单元,直到程序执行完毕才释放。动态存储方式动态存储方式:是在程序运行期间根据需要进行动态分配存储空间的方式。在动态存储区存放如下数据:形参、非静态变量、堆栈(函数调用时的现场保护和返回地址)。动态存储方式根据函数调用的需要,动态地分配和释放存储空间。6.4.3变量的存储类别在C语言中,每一个变量和函数有两个属性:数据类型和存储类别。存储类别分四类存储类别含义auto自动,动态存储方式,可以省略static静态,静态存储方式register寄存器,CPU的寄存器extern外部,声明外部变量auto变量autointb,c=3;intb,c=3;两者等价staticf(inta){autointb=0;

staticintc=3;b=b+1;c=c+1;

return(a+b+c);}main(){inta=2,i;for(i=0;i<3;i++)printf("%d",f(a));}运行结果:789为何结果不是:777呢?

原因:static型变量是在编译时赋初值的,只赋值一次,即在程序运行时它已有初值。

举例打印1~5的阶乘值intfac(intn){staticintf=1;f=f*n;return(f);}main(){inti;for(i=1;i<=5;i++)printf("\n%d!=%d",i,fac(i));}运行结果1!=12!=23!=64!=245!=120慎用static变量static变量长期占用内存,直到程序执行完才释放。降低了程序的可读性。register变量寄存器的存取时间比内存要快C语言允许频繁使用的局部变量的值存放在cpu的寄存器中。registerinti;Turboc将register变量作auto变量处理。用extern声明外部变量编译时,将外部变量(即全局变量)分配在静态存储区。如果外部变量定义处在后或在其他文件中并且使用在前时,则需要对它进行声明。声明分为:1、在一个文件内声明外部变量2、在多文件的程序中声明外部变量声明与定义定义:是定义性声明,需要建立存储空间。定义只能有一次。声明:是引用性声明。声明可以出现多次。声明的作用是一个已在后面定义的外部变量,仅仅是为了“提前”引用该变量而作的“声明”。声明要求外部变量已经定义。例6.13外部变量声明main(){externx,y;intz;z=x*y;printf(\nz=%d",z);}intx=2,y=3;例6.14在多文件的程序中声明外部变量*eg0614a.cinta=4;intmax(intx,inty){return(x>y?x:y);}*eg0614b.cexterna;main(){intx=2,y=3,z;z=x*a+a*y*max(x,y);printf("\nz=%d",z);}6.5内部函数与外部函数1、内部函数2、外部函数1、内部函数如果一个函数只能被本文件中的其他函数调用,而不能被其他文件中的函数调用,这种函数称为内部函数(或称静态函数)。定义内部函数的一般形式是(函数头):static

类型说明符函数名(形参表)2、外部函数若一个函数除了可以被本文件中的其他函数调用外,还可以被程序中的其他源文件的函数调用,这样的函数称为外部函数。它的定义一般形式:extern

类型说明符函数名(形参表)注意:extern可以省略例6.15内部函数与外部函数*eg0615a.cexterninta;externintmax(intm,intn);staticintz=12;staticintmin(intx,inty){return(x<y?x:y);}main(){intx=2,y=3;printf("max=%d,min=%d",max(x,y),min(a,z));}*eg0615b.cinta=10;intmax(intm,intn){if(m>=n)return(m);elsereturn(n);}6.6多文件的程序运行1、工程方法2、文件包含方法1、工程方法2、文件包含方法在eg0615.c的开始添加一行:

#include<eg0615b.c>在文件包含方式中,由于最终生成一个目标文件。所以关于变量、函数的声明都不必要了。6.7预处理命令在前面章节已经使用了如下形式:

#definePI3.14#include<stdio.h>预处理命令ANSIC标准规定可以在C源程序中加入一些“预处理命令”,以改进程序设计环境,提高编程效率。预处理命令不是C语言本身的组成部分,必须在正式编译前进行处理。C提供的预处理功能主要有一下3种:1、宏定义2、文件包含3、条件编译6.7.1宏定义1、不带参数的宏定义2、带参数的宏定义1、不带参数的宏定义一般形式

#define标识符字符串不带参数的宏常用来表示符号常量举例

#definePI3.1415926宏定义的作用宏定义是用宏名代替一个字符串,即只作简单的置换,不作正确性检查。也不分配存储空间。举例

#definePI3.14;area=PI*r*r;展开后如下:

area=3.14;*r*r;/*error*/宏定义的作用域宏名的有效范围为定义命令之后到本源文件结束。可以用#undef命令终止宏定义的作用域。宏的作用域举例#defineG9.8main(){....}#undefGf1(){.....}G的作用范围宏的层层置换#defineR3.0#definePI3.14#defineL2*PI*R#defineSPI*R*Rmain(){printf("\nL=%f\nS=%f",L,S);}注意:双括号括起来的字符串内的字符,即使与宏名相同,也不进行置换。9.1.2带参数的宏定义一般形式

#define宏名(参数表)字符串带参数宏举例(例6.17)#definePI3.14#defineS(r)PI*r*rmain(){floata,area;a=3.6;area=S(a);printf("\nr=%farea=%f",a,area);}area=S(a+3);是否代表圆的面积?带参数宏与函数形式相同,容易混淆不同之处主要有:(1)函数调用需要参数检查;宏只作简单置换。(2)函数调用在程序运行时处理,分配内存单元;宏展开在正式编译前进行,不分配存储单元,无返回值概念。(3)函数调用占运行时间,源程序保持不变;宏展开只占编译时间,展开后源程序变长。举例:可以得到多个结果的宏#definePI3.14#defineCIRCLE(R,L,S)L=2*PI*R;S=PI*R*R;main(){floatr,l,s;printf("\nr=");scanf("%f",&r);CIRCLE(r,l,s);printf("r=%f,l=%f,s=%f",r,l,s);}同时得到了l,s的结果6.7.2“文件包含”处理“文件包含”处理是指一个源文件可以将另外一个源文件的全部包含进来。一般形式

#include"文件名"或

#include<文件名>两种包含形式比较#include<file2.c>:系统到存放C库函数文件所在的目录中寻找要包含的文件,这种称为标准方式。#include"file2.c":系统先在用户当前目录中寻找要包含的文件,如果找不到,再按标准方式查找。“文件包含”的含义file1.c#include<file2.c>file2.cBAfile1.cAB“文件包含”的实质被包含的文件与其所在的文件,在预编译后已经成为同一个文件(而不是两个文件)。被包含的文件的外部变量作用域扩展到了包含文件,所以不必用extern声明。6.7.3条件编译一般情况下,源程序中所有的行都参加编译。但如果对其中一部分内容只在满足一定条件才进行编译,这就是“条件编译”。条件编译形式1)#ifdef标识符程序段1

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论