c语言 第6章.ppt_第1页
c语言 第6章.ppt_第2页
c语言 第6章.ppt_第3页
c语言 第6章.ppt_第4页
c语言 第6章.ppt_第5页
已阅读5页,还剩75页未读 继续免费阅读

下载本文档

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

文档简介

1、,6.1 概述 6.2 函数的定义 6.3 函数的调用 6.4 变量的作用域和存储类别 6.5 内部函数和外部函数 6.6 函数的嵌套调用和递归调用,第六章 函数,模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 各模块相对独立、功能单一、结构清晰、接口简单 控制了程序设计的复杂性 提高元件的可靠性 缩短开发周期 避免程序开发的重复劳动 易于维护和功能扩充 开发方法: 自上向下,逐步分解,分而治之,6.1 概述,C是模块化程序设计语言,C是函数式语言 必须有且只能有一个名为main的主函数 C程序的执行总是从main函数开始,在main中结束,函数分类 从用户角度 标准

2、函数(库函数):由系统提供 用户自定义函数 从函数形式 无参函数 有参函数,6.1 概述 6.2 函数的定义 6.3 函数的调用 6.4 变量的作用域和存储类别 6.5 内部函数和外部函数 6.6 函数的嵌套调用和递归调用,第六章 函数,6.2 函数的定义 6.2.1 一般格式,合法标识符,函数返回值类型 缺省int型 无返回值void,函数体,函数类型 函数名(形参类型说明表) 说明部分 语句部分 ,例 有参函数 int max(int x,int y) int z; z=xy?x:y; return(z); ,例 无参函数 printstar( ) printf(“*n”); 或 prin

3、tstar(void ) printf(“*n”); ,6.2.2 函数的返回值 返回语句 形式: return(表达式); 或 return 表达式; 或 return; 功能:使程序控制从被调用函数返回到调用函数中,同时把返值带给调用函数 说明: 函数中可有多个return语句 若无return语句,遇到函数结束的“”时,自动返回调用函数 若函数类型与return语句中表达式值的类型不一致,按前者为准,自动转换-函数调用转换 void型函数:无返回值的函数,例 无返回值函数 void swap(int x,int y ) int temp; temp=x; x=y; y=temp; ,pr

4、intstar() printf(*); main() int a; a=printstar(); printf(%d,a); ,例 无返回值的函数返回后带回不确定值,输出:10,void printstar() printf(*); main() int a; a=printstar(); printf(%d,a); ,编译错误!,例 函数返回值类型转换,main() float a,b; int c; scanf(%f,%f, ,6.1 概述 6.2 函数的定义 6.3 函数的调用 6.4 变量的作用域和存储类别 6.5 内部函数和外部函数 6.6 函数的嵌套调用和递归调用,第六章 函数,

5、6.3 函数的调用 6.3.1 调用形式: 函数名(实参表),函数语句:函数调用可单独成为一个语句 例 output(); printf(“Hello,World!n”); 函数表达式: 调用函数后的返回值可参加表达式的计算,这时要求被调函数带返回值。 例 sum=add(a,b); c=fac(n)/(fac(k)*fac(n-k) ; 函数参数:带返回值的函数调用亦可作为其它函数的参数(实际参数) 例 printf(“%d”,max(a,b); m=max(a,max(b,c);,调用方式 函数语句:函数调用可单独成为一个语句 例 output(); ; printf(“Hello,Wor

6、ld!n”); 函数表达式: 调用函数后的返回值可参加表达式的计算,这时要求被调函数带返回值。 例 sum=add(a,b); c=fac(n)/(fac(k)*fac(n-k) ; 函数参数:带返回值的函数调用亦可作为其它函数的参数(实际参数) 例 printf(“%d”,max(a,b); m=max(a,max(b,c);,调用函数的过程是: 为函数的所有形参分配内存单元。 计算各个实参表达式的值,一一对应的赋值给相应形参(若是无参函数,上述过程不执行)。 进入函数体,执行函数中的语句,实现函数的功能。 执行到return语句时,计算return语句中表达式的值(若是无返回值函数,本项不

7、做),返回到主调函数。 释放形参及本函数内的局部变量所占内存, 继续执行主调函数中的后继语句。 说明: 实参与形参个数相等,类型一致,按顺序一一对应 形参与实参的结合顺序,因系统而定(Turbo C 自右向左),main() int i=2,p; p=f(i,+i); printf(%d,p); int f(int a, int b) int c; if(ab) c=1; else if(a=b) c=0; else c=-1; return(c); ,例 参数求值顺序,main() int i=2,p; p=f(i, i+); printf(%d,p); int f(int a, int b

8、) int c; if(ab) c=1; else if(a=b) c=0; else c=-1; return(c); ,运行结果:0,运行结果:1,对于函数的位置: 对于非int函数,调用单位的位置要在被调用单位在下面,否则编译产生错误。 解决方法是:在调用单位加上被调用函数的声(说)明。,6.3.2 函数说明 对被调用函数要求: 必须是已存在的函数 库函数: #include 用户自定义函数: 函数类型说明 函数说明 一般形式: 函数类型 函数名(形参类型 形参名,. ); 或 函数类型 函数名(); 作用:告诉编译系统函数类型、参数个数及类型,以便检验; 函数定义与函数说明不同; 函数

9、说明位置:程序的数据说明部分(函数内或外); 下列情况下,可不作函数说明 若函数返值是char或int型,系统自动按int型处理; 被调用函数定义出现在主调函数之前; 有些系统(如Borland C+)要求函数说明指出函数返值类型和形参类型,并且对void 和 int 型函数也要进行函数说明,例 函数说明举例,C语言中,函数调用是值传递方式,即函数的实际参数和形式参数之间的数据传递方向是单向的,只能由实际参数传递给形式参数,而不能由形式参数传递给实际参数,是实际参数向形式参数单向赋值的关系。 在内存中,形式参数与实际参数占用不同的内存单元。当调用函数时,给形式参数分配内存单元,将实际参数的值赋

10、值给形式参数,调用后,形式参数单元释放,实际参数仍保留调用前的值,形式参数值的变化不影响实际参数。,6.3.3 函数参数及其传递方式 形参与实参 形式参数:定义函数时函数名后面括号中的变量名 实际参数:调用函数时函数名后面括号中的表达式,例 比较两个数并输出大者,main() int a,b,c; scanf(%d,%d, ,说明: 实参必须有确定的值 形参必须指定类型 形参与实参类型一致,个数相同 若形参与实参类型不一致,自动按形参类型转换函数调用转换 形参在函数被调用前不占内存;函数调用时为形参分配内存;调用结束,内存释放,例 计算x的立方,#include float cube(floa

11、t x) return(x*x*x); main() float a, product; printf(Please input value of a:); scanf(%f, ,x,1.2,1.2,1.728,参数传递方式 值传递方式 方式:函数调用时,为形参分配单元,并将实参的值复制到形参中;调用结束,形参单元被释放,实参单元仍保留并维持原值 特点: 形参与实参占用不同的内存单元 单向传递,交换两个数,#include main() int a=3,b=5; printf(“a=%d,tb=%dn,a,b); printf(swapped:n); swap(a,b); printf(“a=

12、%d,tb=%dn,a,b); swap(int x,int y) int temp; temp=x; x=y; y=temp; ,如何实现“地址传递”? 只能是:函数调用时,将数据的存储地址作为参数传递给形参,当然此时的行参只能是能存储地址的变量(指针变量)。才能达到“双向”传送的目的。,swap(p1,p2) int *p1,*p2; int p; p=*p1; *p1=*p2; *p2=p; main() int a,b; scanf(%d,%d, ,例 交换两个数,6.1 概述 6.2 函数的定义 6.3 函数的调用 6.4 变量的作用域和存储类别 6.5 内部函数和外部函数 6.6

13、函数的嵌套调用和递归调用,第六章 函数,6.4 变量的作用域和存储类别 变量是对程序中数据的存储空间的抽象,编译或函数调用时为其分配内存单元,10,程序中使用变量名对内存操作,变量的属性 数据类型:变量所持有的数据的性质(操作属性) 存储属性 存储器类型:寄存器、静态存储区、动态存储区 生存期:变量在某一时刻存在-静态变量与动态变量 作用域:变量在某区域内有效-局部变量与全局变量 变量的存储类型 auto -自动型 register-寄存器型 static -静态型 extern -外部型 变量定义格式: 存储类型 数据类型 变量表;,如: int sum; auto int a,b,c; r

14、egister int i; static float x,y;,变量的作用域 程序中所声明的在程序的那一部分中是可用的。 只有在自己的作用域中才可用。,从作用域角度考虑分为:内部变量、外部变量 内部变量(局部变量)的作用域:是定义它的函数内或复合语句内,在它的作用域之外,内部变量是不可见的,也就是说,一个函数内定义的内部变量是不能被其它的函数所引用的。 特性:有助实现信息隐蔽,即使不同的函数定义了同名的内部变量,也不会相互影响。,内部变量-局部变量 定义:在函数内定义,只在本函数内有效 说明: main中定义的变量只在main中有效 不同函数中同名变量,占不同内存单元 形参属于局部变量 可定

15、义在复合语句中有效的变量 局部变量可用存储类型:auto register static (默认为auto),复合语句中变量 #define N 5 main() int i; int aN=1,2,3,4,5; for(i=0;iN/2;i+) int temp; temp=ai; ai=aN-i-1; aN-i-1=temp; for(i=0;iN;i+) printf(%d ,ai); ,运行结果:5 4 3 2 1,例 不同函数中同名变量 main() int a,b; a=3; b=4; printf(main:a=%d,b=%dn,a,b); sub(); printf(main:

16、a=%d,b=%dn,a,b); sub() int a,b; a=6; b=7; printf(sub:a=%d,b=%dn,a,b); ,运行结果: main:a=3,b=4 sub:a=6,b=7 main:a=3,b=4,外部变量(全局变量) 定义:在函数外面定义的变量。 外部变量的作用域:对于只有一个源程序文件构成的程序,外部变量的作用域是从定义它的位置开始,直至它所在源程序文件的结束。 特点:外部变量的使用增加了函数之间传递数据的途径,在外部变量的作用域内的任何函数都能引用该外部变量,一个函数对外部变量的修改,能影响到其它引用这个变量的函数;因此对外部变量的使用不当,会产生意外的错

17、误。,float max,min; float average(int n) int i; float x; scanf(“%f”, ,int a=3,b=5; max(int a, int b) int c; c=ab?a:b; return(c); main() int a=8; printf(“a=%dn,b=%dn,max=%dn, a,b,max(a,b); ,外部变量与局部变量同名时,在内部变量的作用域中, 外部变量被屏蔽。 例:,运行结果: a=8 /*main中的a*/ b=5 /*main中的b*/ max=8,int i; main() void prt(); for(i=

18、0;i5;i+) prt(); void prt() for(i=0;i5;i+) printf(“%c”,*); printf(“n”); ,外部变量使用不当时,会引起副作用。,运行结果:*,外部变量的作用域可以通过关键字“extern”来扩展:,int max(int x, int y) int z; z=xy?x:y; return(z); main() extern int a,b; printf(max=%d,max(a,b); int a=13,b=-8;,运行结果:max=13,extern int a,b; int max() int z; z=ab?a:b; return(z

19、); main() printf(max=%d,max(); int a=13,b=-8;,main() void gx(),gy(); extern int x,y; printf(“1: x=%dty=%dn”,x,y); y=246; gx(); gy(); void gx() extern int x,y; x=135; printf(“2: x=%dty=%dn”,x,y); int x,y; void gy() printf(“3: x=%dty=%dn”,x,y); ,用extern扩展外部变量作用域例子:,运行结果: 1: x=0 y=0 2: x=135 y=246 3: x

20、=135 y=246,外部变量(全局变量)继续: 对于多文件程序,在一个源文件中定义的外部变量还可以在其它的文件中使用,这时需要在使用它的文件中用extern进行说明,这样的变量称为程序级的变量。,应尽量少使用全局变量,因为: 全局变量在程序全部执行过程中占用存储单元 降低了函数的通用性、可靠性,可移植性 降低程序清晰性,容易出错,定义 说明 次数: 只能1次 可说明多次 位置: 所有函数之外 函数内或函数外 分配内存: 分配内存,可初始化 不分配内存,不可初始化,外部变量定义与外部变量说明不同: 在同一个文件中,定义在后使用在前的外部变量,在使用前需要对其进行声明。 在包含多个文件的程序中,

21、一个文件若使用其它文件中定义的外部变量也要进行声明。 外部变量说明: extern 数据类型 变量表;,C语言中,按作用域的大小,可将变量的作用域分为四个级别:程序级、文件级、函数级、复合语句级。这是由C程序的结构特点所决定的。,5.3.2 变量的存储类别-动态变量与静态变量 动态变量:动态存储类别的变量当进入定义它的函数或复合语句时被分配存储空间,当离开时所占内存空间被释放。 静态变量:静态存储类别的变量在源程序编译的时候被分配固定的存储空间,从程序开始执行到程序运行结束,一直占用该内存空间,直至程序运行结束,才被释放内存空间。,生存期-变量存在(在内存有存储空间)的时间段。 静态变量:从程

22、序开始执行到程序结束 动态变量:从包含该变量定义的函数开始执行至函数执行结束,5.3.3 内部变量的存储类别 内部变量的作用域是定义它的函数或复合语句。内部变量的存储类别是指它存放的位置。内部变量可存放于内存的动态区,寄存器和内存的静态区。但无论内部变量存放在何处,它的作用域是不变的。 内部变量可以定义为: 自动的(auto ) 寄存器(register ) 静态的(static ) 自动的(auto ):在函数内定义的变量都是自动的。 main() int a; /*等价于:auto int a;*/ 寄存器变量(register ) 如:register int i;,例 auto 变量的

23、作用域,main() int x=1; void prt(void); int x=3; prt(); printf(“2nd x=%dn”,x); printf(“1st x=%dn”,x); void prt(void) int x=5; printf(“3th x=%dn”,x); ,运行结果: 3th x=5 2nd x=3 1st x=1,静态的(static ): 如:static int i;,下次再调用该函数时,staic变量仍使用原来的存储单元,仍使用原来存储单元中的值。,分配内存后、赋初值,并且只被赋初值一次,未赋值的内部staic变量,系统自动给它赋值为0。,被分配在内存

24、的静态存储区中。,staic变量在内存的静态存储区占用的固定的内存单元;即使它所在的函数被调用结束后,也不释放存储单元,它所在单元的值也会继续保留-因此:,虽然staic变量在整个程序运行期间都是存在的,但在它的作用域外,它是不可见的,也就是说其它函数是不能引用它的。,main() void increment(void); increment(); increment(); increment(); void increment(void) int x=0; x+; printf(“%dn”,x); ,例 局部静态变量值具有可继承性,运行结果:1 1 1,main() void increm

25、ent(void); increment(); increment(); increment(); void increment(void) static int x=0; x+; printf(“%dn”,x); ,运行结果:1 2 3,#includestdio.h void test_a_s() auto int auto_v=0; /*内部自动的*/ static int static_v=0; /*内部静态的*/ printf(nauto_v=%d,static_v=%d,auto_v,static_v); auto_v+; static_v+; main() int i; for(

26、i=0;i3;i+) test_a_s(); ,例 5.8,运行结果:,auto_v=0,static_v=0 auto_v=0,static_v=1 auto_v=0,static_v=2,利用静态变量的情况: long func(long i) static long k=1; k=k*i; return (k); main() long n,m; printf(n); scanf(%ld, ,例 5.9计算 1!、2!、3!、n!(n的值由键盘输入),不利用静态变量的情况: long func(long n) long k=1;int i; for(i=1;i=n;i+) k=k*i;

27、return (k); main() long n,m; printf(n); scanf(%ld, ,5.3.4 外部变量的存储类别 外部变量只能存放在内存的静态存储区 。它在整个程序的运行期间一直占用内存单元。 外部变量的作用域可以通过关键字“extern”来扩展。 (扩展至某个文件,甚至被其它源程序文件使用) 用static声明的外部变量能够限制它的作用域的扩展,达到信息隐蔽的目的。, 在同一个文件中,定义在后使用在前的外部变量,在使用前需要对其进行声明。 在不同文件中(但同属一个程序),使用其它文件中定义的外部变量(但是不要企图使用static声明了的外部变量)。,/*p5-1002.

28、c*/ int Max; void func(int x,int y,int z) extern int Min; Max=x; Min=x; if(yMax) Max=y; if(zMax) Max=z; if(yMin) Min=y; if(zMin) Min=z; int Min;,例 5.10 该程序包括两个文件p5-1001.c和p5-1002.c,并且文件 p5-1001.c使用p5-1002.c中的外部变量,因此要在文件p5-1001.c中对该外部变量进行声明。,/*p5-1001.c*/ #includep6-1402.c extern int Max,Min; main()

29、void func(int x,int y,int z); int a,b,c; printf( a,b,c=?); scanf(%d,%d,%d, ,变量存储类型,局部变量默认为auto型 register型变量个数受限,且不能为long, double, float型 局部static变量具有全局寿命和局部可见性 局部static变量具有可继承性 extern不是变量定义,可扩展外部变量作用域,例 文件file1.c int a; main( ) . . f2; . f1; . f1( ) auto int b; f2; . f2( ) static int c; ,例 变量的寿命与可见性

30、,#include int i=1; main() static int a; register int b=-10; int c=0; printf(-MAIN-n); printf(i:%d a:%d b:%d c:%dn,i,a,b,c); c=c+8; other(); printf(-MAIN-n); printf(i:%d a:%d b:%d c:%dn,i,a,b,c); i=i+10; other(); ,other() static int a=2; static int b; int c=10; a=a+2; i=i+32; c=c+5; printf(-OTHER-n);

31、 printf(i:%d a:%d b:%d c:%dn,i,a,b,c); b=a; ,-Main- i:1 a:0 b:-10 c:0,-Other- i:33 a:4 b:0 c:15,-Main- i:33 a:0 b:-10 c:8,-Other- i:75 a:6 b:4 c:15,8,4,33,15,4,43,6,75,15,6,例 引用其它文件中的变量,输出ab和a的m次方,5.4 内部函数和外部函数,5.4.1 外部函数 外部函数是可以被程序中的其它文件所调用的函数。 定义格式如下: extern 数据类型 函数名(形式参数表列) 说明部分; 执行部分; ,外部函数是C语言默

32、认的函数类型,若没有特别的声明为extern类型,系统也会默认为外部函数。,5.4.2 内部函数 内部函数是只能被本文件中其它函数调用,而不能被其它文件调用的函数。 它的定义格式如下: static 数据类型 函数名(形式参数表列) 说明部分; 执行部分; ,5.5 函数的嵌套与递归调用 嵌套调用 C规定:函数定义不可嵌套,但可以嵌套调用函数,例 求三个数中最大数和最小数的差值,#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

33、a,b,c,d; scanf(%d%d%d, ,int dif(int x,int y,int z) return 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); ,例 用弦截法求方程根,运行情况: Input x1,x2: 2,6 A root of equation is 5.0000,递归调用 定义:函数直接或间接的调用自身叫函数的递归调用,说明 C编译

34、系统对递归函数的自调用次数没有限制 每调用函数一次,在内存堆栈区分配空间,用于存放函数变量、返回值等信息,所以递归次数过多,可能引起堆栈溢出,int f(int x) int y,z; z=f(y); . return(2*z); ,例 求n的阶乘,/*ch7_8.c*/ #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:);

35、 scanf(%d, ,Hanoi(汉诺)塔问题: 古代有一个梵塔,塔内有三各底座A、B、C。开始时A座上有64个盘子,牌子大小不等,大的在下,小的在上。有一个老和尚想把这64个盘子从A座移到C座上去,每一次只允许移动一个盘子,且在移动过程中每个底座上的盘子必须是大的在下,小的在上。,老和尚自然这样想:假若有另外一个和尚想办法将63个盘子从一个地座上,那么问题就解决了。老和尚只需这样做: (1)命令第二个和尚将63个盘子从A移到B座; (2)自己将最底下的最大的那一个盘子从A移到C座; (3)再命令第二个和尚将63个盘子从B移到C座; 任务就完成了。,第二个和尚自然这样想:假若有第三个和尚想办

36、法将62个盘子从一个地座上,那么问题就解决了。第二个和尚只需这样做: (1)命令第三个和尚将62个盘子从A移到C座; (2)自己将最底下的最大的那一个盘子从A移到B座; (3)再命令第二个和尚将62个盘子从C移到B座; 这样第二个和尚的任务就完成了。,这样以此类推,层层下放,直到第63个和尚找到第64个和尚,第64个和尚的任务是将一个盘子移到另一座上,第63个和尚再完成自己的任务;第62个和尚再完成自己的任务;老和尚才能完成自己的任务。 以3个盘子为例,步骤为: A-C, A-B, C-B, A-C, B-A, B-C, A-C,例5.14 Hanoi问题,void move(char get

37、one, char putone) printf(%c-%cn,getone,putone); void hanoi(int n,char one,char two,char three) if(n=1) move(one,three); else hanoi(n-1,one,three,two); move(one,three); hanoi(n-1,two,one,three); main() int m; printf(Input the number of disks:); scanf(%d, ,6.7 数组作为函数参数 数组元素作函数实参值传递,例 两个数组大小比较,n=0 m=0 k=0,a和b为有10个元素的整型数组 比较两数组对应元素 变量n

温馨提示

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

最新文档

评论

0/150

提交评论