西安交大语言课件第四章函数_第1页
西安交大语言课件第四章函数_第2页
西安交大语言课件第四章函数_第3页
西安交大语言课件第四章函数_第4页
西安交大语言课件第四章函数_第5页
已阅读5页,还剩74页未读 继续免费阅读

下载本文档

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

文档简介

1、第四章 函数西安交通大学程序设计基础课程组2008本章要点函数概述函数定义函数参数与函数的返回值函数的调用函数嵌套调用和递归调用变量作用域变量存储类别与生存周期内部函数和外部函数问题的提出:在实际应用中,需要解决的问题很复杂或很庞大时,编程怎么实现?从哪里入手?代码量太大功能太复杂一个人不能胜任用一个main()实现需要多长代码?分而治之(模块化)模块化的优点:模块各司其职每个模块只负责一件事情,它可以更专心便于进行单个模块的设计、开发、调试、测试和维护等工作一个模块一个模块地完成,最后再将它们集成开发人员各司其职按模块分配任务,职责明确并行开发,缩短开发时间假如不采用模块化?main()当中

2、能放多少行程序?读多少行的程序能让你不头疼?假如printf()函数由10行代码替换,那么你见过的程序会成什么样子?如果所有代码都在main()当中,如果代码都在一个文件中,怎么团队合作?函数和模块化有什么关系?函数是C语言中模块化编程的最小单位函数(function)和 模块(module)可以把每个函数看作一个模块若干相关的函数可以合并作一个“模块”main()printf()scanf()power()putchar()getchar()main()stdio:printf()scanf()putchar()getchar()mymdl:power()4.1 函数概述在实际应用中,对于一

3、个问题很复杂或很庞大时,一般是将其分解为若干相对小且简单的子问题进行解决。每一个子问题的在C语言中是用函数描述的。因此,人们称C语言程序是由一系列函数组成的,由此也可以看出C语言是支持结构化程序设计的。 自顶向下逐步求精4.1 函数概述总任务子任务1子任务2子任务n子任务21子任务22子任务n1子任务n2子任务n3子任务221图1 结构化任务划分示意4.1 函数概述C语言中的函数分为两类:由系统提供的标准库函数由程序员自定义的函数函数的主要作用是用来完成重复任务,或者完成具有独立功能的模块。在C语言中,程序是由一个主函数main( )和其他若干函数构成的。在主函数main( )中可以调用其他函

4、数(调用函数即执行函数),其他函数之间也可以互相调用。函数之间的调用关系如图2所示:4.1 函数概述主函数子函数1子函数2子函数n子函数21子函数22子函数n1子函数n2子函数n3子函数221图2 函数之间的调用关系示意图4.1 函数概述一个C程序可以由一个或多个函数组成;一个C程序必须从main()函数开始执行。 函数间可以相互调用,但不能调用main函数,它是由系统调用的;函数又分为如下两类:无参函数和带参函数。参数用来向函数传递不同的数据。函数都可以返回或不返回一个函数值。返回一个函数值可供调用它的函数使用,或者用来判断函数的执行状态。4.2.1 函数的定义形式 () 用括起,表示该部分

5、内容可以省略; 用括起,表示这部分是必要的。4.2 函数定义4.2 函数定义说明:1、用于确定这个函数的返回值的类型,如整型、实型、字符型等。默认类型是int型。2、定义了函数的名称,通过这个名称才能对某个函数进行调用。 3、规定了函数有什么样的参数。形式参数的作用是控制函数进行什么样的操作,它们的值由调用这个函数的程序给出。根据函数有无参数,又可以把函数分为无参函数和有参函数,若形式参数有多个,则形式参数之间用逗号隔开,由主调函数通过参数向被调函数传递数据。4.2.1 函数的定义形式4. 部分规定了形式参数的类型。形参与形参的类型说明可以分开描述,如:fun (x, y, z) int x,

6、 y, z;也可以放在一起,写成:fun (int x, int y, int z)5. 规定了在函数内部要用到的变量以及它们的类型。6. 规定了函数中要执行的语句。函数体语句和变量定义部分用一对大括号括起来。函数名命名Windows风格函数名命名用大写字母开头的单词组合而成 变量名形式“名词”或者“形容词+名词”如变量名oldValue与newValue等函数名形式“动词”或者“动词+名词”(动宾词组)如函数名GetMax()等 4.2.1 函数的定义形式例4.2 关于函数的定义。 int max(x, y) int x, y; int t; t = (xy) ? x:y ; return(

7、t); main( ) int a, b, c; scanf (“%d, %d”, &a, &b); c = max(a, b); printf (“This max is: %dn”, c); 类型说明符X,y是形式参数无返回值无形式参数形式参数类型说明函数名a,b是实参4.2.1 函数的定义形式(2)a,b是实在参数;c为main函数中的局部变量x,y是形式参数; t为max函数中的局部变量 程序执行顺序: 运行主程序main() 当执行c=max(a,b)语句时,调用函数max max函数的运行结果由return语句返回 main函数中输出结果4.2.2 空函数按如下方式定义的函数称为空

8、函数: ( ) 在结构化程序设计中,可将那些功能较复杂、作用较为次要的函数先定义成空函数,集中精力编写那些基本的、常用的函数,边编写边调试。最后再一步一步的完善各个函数。这样的程序可读性好,易调试,易维护,易扩充。4.3 函数参数与函数的返回值4.3.1 形式参数与实在参数1. 形式参数在定义函数时函数名后括号内的变量表列就称为形式参数表。只有当函数被调用时,形参才在内存中开辟空间。调用结束后,形参自动从内存中被释放掉。 2、实在参数在调用函数时函数名后括号内的变量表列被称为实在参数表。K4-14.3.1 形式参数与实在参数2. 实在参数实参的作用是给相应的形参赋值,所以在调用函数前,实参必须

9、要有一个确切的值,它可以是常量、变量或表达式。实参与形参的关系是单向赋值的关系。3. 形参类型在函数定义中,必须规定形参的类型。有两种定义方式,如:int max(x, y, z) 或int max(int x, int y, float z)int x, y; float z; 4.3.1 形式参数与实在参数4. 实参与形参的结合:单向赋值传递!例4.3 关于实参与形参的结合的例子。 int echonum( int i, int j ) int t; t = i; i = j; j = t; printf(“In function i = %d, j = %dn”, i, j); main

10、( ) int i = 6, j = 8; echonum(i, j); printf(“Out function i = %d, j = %dn”, i, j); 程序运行结果: In function i = 8, j = 6 Out function i = 6, j = 8EX4-34.3.2 函数的返回值return语句的一般格式如下: return (); 或 return ;它的功能是将表达式的值作为函数的返回值返回,结束本次函数调用并回到调用函数语句。return;如果只想从函数返回而不想带回返回值,可以使用不带表达式的方式,也可以省略不写return语句。void echol

11、ine(); 明确函数无返回值不加类型说明的函数,自动按整形处理。但TC+3.0要求必须指定函数类型,否则编译不通过。函数返回值的说明:1、函数中可以有多个return语句,执行到哪个return语句,就从那一个return语句返回。2、return只能返回一个值,而不能返回多个值。3、return(表达式) 语句中的表达式值的类型应与定义函数时函数的类型一致。K4-24.4 函数的调用4.4.1 函数调用格式函数调用的一般格式: ()有多个实参,要用逗号将实参变量隔开;实参和形参必须个数相等,顺序依次对应。当实参和对应形参类型不一致时,先将实参的类型转换成形参的类型后再传递。如果这个函数是无

12、参函数,那么实参表列可以省略,但括号不能省略。4.4.1 函数调用格式在C语言中,我们可以将函数调用当成一个表达式,如果在这个表达式后加一个分号,就成为函数调用语句;函数实参的求值顺序在各C语言系统中是不一样的,有的是从左到右,有的是从右到左。参见书P1114.4.2 函数调用规则被调用函数必须是已经存在的函数、库函数或用户已定义过的函数。如果使用库函数,还要在使用库函数的源文件开头用#include声明库函数所在的头文件。如果使用用户自定义的函数,还要在主调函数中说明用户函数的返回值类型,函数说明的一般形式为: ( );4.4.2 函数调用规则C语言规定在以下几种情况中,可以不在主调函数中说

13、明函数的返回值类型:如果被调用函数的返回值为整型或字符型时,可不进行说明。如果被调用函数在主调函数之前定义,也可不进行说明。推荐在程序的开头对程序中的所有函数进行定义;P112例4.44.5 函数的嵌套调用和递归调用调用关系上来看,函数之间就存在两种关系:嵌套关系和递归关系。 4.5.1 函数的嵌套调用函数的嵌套调用表现在某个函数在执行过程中,又可以调用另外一个函数。也就是说,函数在执行过程中,不是执行完一个函数再去执行另一个函数而是可以在任何需要的时候对其他函数进行调用。4.5.1 函数的嵌套调用例4.7 关于函数的嵌套调用 #include main( ) int i , j , k; i

14、 = 0; j = 1; k = 2; k = q(0, k); printf(“%4d %4d %4dn”, i,j,k); k = q(1, k); printf(“%4d %4d %4dn”, i,j,k); j = q(2, j); printf(“%4d %4d %4dn”, i,j,k); EX4-74.5.1 函数的嵌套调用 int q(int h, int j) int i; i = j; if (h = 0) j = p(j); else i = p(i); printf(“%4d %4d %4dn”, i, j, h); return(j); int p(int i) re

15、turn(+i); 运行结果:230013431013212013EX4-74.5.1 函数的嵌套调用 下图给出例4.7程序执行的流程。序号表示执行的先后关系。main( )函数调用q( )函数main( )函数结束q( )函数p( )函数调用p( )函数q( )函数结束p( )函数结束123456789从图中可以看出,函数在执行过程中可以对另一函数进行调用,即实现了函数的嵌套调用。4.5.2 函数的递归调用如果在调用函数时,被调用函数又是函数本身,那么这种调用就被称为函数的递归调用。函数的递归调用分直接递归调用和间接递归调用。如果在调用函数的本身又出现直接调用该函数本身,则称为函数的直接递归

16、调用;如果在调用函数的本身又出现间接调用该函数本身,则称为函数的间接递归调用。P116例4.84.5.2 函数的递归调用采用递归方法解决的问题一般应符合以下条件:可以把该问题化为一个新问题,新问题的解决方法与原问题的解决方法相同,只是所处理的对象有规律的递增或递减,相对简单一些。通过转换最终使问题得到解决。必须有一个结束递归的条件。因此,递归程序由两大部分构成:当某一条件成立时不再进行递归调用,即结束递归。当条件不成立时仍然进行递归调用。4.5.2 函数的递归调用例4.9 n的阶乘可以采用两种形式定义: (1) n! = 1 * 2 * 3 * 4 * * n (2) 1 当n = 1时 f(

17、n)= n! = n * f(n-1) 当n 1时 第二种就是递归定义。程序如下:long facl( int n ) long f; if (n = 1) f = 1; else f = n * facl(n-1); return ( f ) ; 4.5.2 函数的递归调用例4.10 在进行人口普查时,人口普查员问一户农家的主人:“你家有几个孩子?”主人答:“五个”,“您大孩子多大了?”“比老二大两岁”,“那老二多大了?”“比老三大两岁”,“那老三多大了?”“比老四大两岁”,“那老四多大了?”“比老五大两岁”,“那老五多大了?”“老五一岁了”这时才知道老大九岁了。我们可以列一组式子:AGE(

18、1) = AGE(2) +2; AGE(2) = AGE(3 )+2; AGE(3) = AGE(4) +2; AGE(4) = AGE(5) +2; AGE(5) = 1;P117例4.104.5.2 函数的递归调用简化一下,可得到如下的数学式子: 1 N = 5 AGE(N) = AGE(N+1)+2 1N0 这个过程就是递归的过程,程序如下:float power( float x, int n ) float y; printf(“begin n=%dn”,n); if (n = 0) y = 1; else y = x * power(x,n-1); printf(“end n=%d

19、n”,n); return ( y ) ; 4.5.2 函数的递归调用 main( ) float z , t ; t = 2. 0; z = power(t ,3); printf(“z=%5.1f n”, z ); 运行结果: begin n=3begin n=2 begin n=1begin n=0 end n=0 end n=1 end n=2 end n=3 z=8.0 下面讲变量的分类:从变量的作用域分:全局变量局部变量从变量存储类别和生存周期分:静态存储类型动态存储类型4.6 变量作用域任何一个变量都是有它的管辖范围,也称为变量的作用域。只有在变量的作用域范围内才能使用这个变量。

20、在C语言中如果按作用域分,变量分为局部变量和全局变量。4.6.1 局部变量在一个函数内部定义的变量被称为局部变量局部变量只能在定义它的函数内部使用,而不能在其它函数内使用这个变量。4.6.1 局部变量说明:main函数内部定义的变量只能在main函数内部使用,而在其它函数内部不能使用main函数内部定义的变量。不同的函数中可以使用相同的变量名,但它们是属于不同函数的变量,它们的作用域是不同的,在不同的区域内分配空间。形参也属于局部变量,作用范围在定义它的函数内,在定义形参和函数体内的变量不能重名;P119 4.6.14.6.2 全局变量例4.11 关于全局变量int x, y;/*外部变量*/

21、 float f1(int a) float a, b; int f2(int c) 全局变量x,y int z ;的作用范围 全局变量a,b main( )的作用范围 int m, n ; 在函数外部定义的变量称为外部变量,外部变量属于全局变量。全局变量的作用域是从定义变量的位置开始到本源文件结束。4.6.2 全局变量说明:1、在一个函数内部,既可以使用本函数定义的局部变量,也可以使用在此函数前定义的全局变量。2、全局变量的作用是使得函数间多了一种传递信息的方式。如果在一个程序中各个函数都要对同一个信息进行处理,就可以将这个信息定义成全局变量。例4.12 对一个数组进行排序,排序结果显示在屏

22、幕上。要求用函数来实现。EX4-12void sort( );void echoa( );int a5 = 5, 6, 7, 3, 2;main( ) echoa( ); sort( ); echoa( );void echoa( ) int i; for(i = 0; i5; i +) printf(“%3d”, ai); printf(“n”); int n=5;void sort( ) int i, j, min, t; for(i=0;in-1;i+) min=i; for(j=i+1;jn;j+)if(ajamin) min = j; t = ai; ai = amin; amin

23、= t; 程序运行结果:5 6 7 3 2 2 3 5 6 7第 i 轮置换后,ai是余下的(n-i)个数中最小的,即依次求出第一个、第二个、第n个最小的数4.6.2 全局变量优点:全局变量使函数之间的数据交换更容易,也更高效可以使用全局变量减少函数实参和形参个数缺点:谁都可以改写全局变量,所以很难确定是谁改写了它全局变量在全部执行过程中都占用存储单元不推荐使用全局变量!4.6.2 全局变量用extern定义外部变量的一般格式: extern 其作用是告诉系统这个函数中使用的变量是外面定义的全局变量,它在内存中不产生新的变量。如果在一个函数内部,一个局部变量和全局变量重名,那么是局部变量起作用

24、,而外部变量不起作用。P122 4.144.6.2 全局变量程序如下:int a =3, b =5;int max(a, b)int a, b; return (ab ? a : b);main( ) int a = 8; printf(“%d”, max(a, b); 程序运行结果:8例4.14 关于全局变量和局部变量重名的例子。思考:为什么全局变量的作用域是从定义变量的位置开始到本源文件结束,甚至可以是在多个文件中使用?为什么局部变量只能在在定义它的函数内部使用?实际上取决于变量在内存中的存储类型4.7 变量存储类别与生存周期系统开机后,内存被分为两大块。一块是系统区,存放操作系统等内容;

25、另一块是用户区,用来存放被执行的用户程序。一个C程序在运行时,用户区被分为三大块:程序区静态存储区动态存储区 用来存放C程序运行代码 用来存放全局变量 用来存放如形参、函数体内部定义的局部变量动态存储是根据需要临时分配存储空间,离开即释放静态存储是在程序运行期间分配固定的存储空间不释放4.7 变量存储类别与生存周期变量的存储类型指数据在内存中存储的方式,即编译器为变量分配内存的方式,它决定变量的生存期。程序运行期间变量在内存中存在的时间称为变量的生存周期。静态存储类别的生存周期是固定的,动态存储类别的生存周期是根据变量调用而定除了前面讲的外部变量extern(全局变量)和形参的声明,还有哪些方

26、式可以确定它的存储类别?4.7 变量存储类别与生存周期在C语言中,每一个变量都有两个属性:数据类型数据的存储类别在C语言中,共有四种存储类别:自动存储类别(auto)局部变量寄存器存储类别(register)外部存储类别(extern)全局变量静态存储类别(static)4.7 变量存储类别与生存周期程序区静态存储区动态存储区局部变量(形参)、自动变量、函数调用的现场、寄存器存储类别外部存储类别、全局变量和静态存储类别的变量4.7.1 静态存储变量static凡是用关键字static定义的变量全部被称为静态变量;静态存储变量又分为:局部静态存储变量全局静态存储变量它们都存储在静态存储区内,在程

27、序的整个运行期间这些静态变量都存在。都用static声明,声明的位置不同一个是函数前面,一个是函数内部4.7.1 静态存储变量static局部静态变量指的是在函数中用关键字static定义的变量,其作用范围是从定义它的函数时起作用;局部静态变量存储在静态存储区,在函数返回时这个静态变量不会被释放,仍然保存它的值。如果再次调用这个函数时,我们就可以直接使用这个保存下来的值。这是和前面讲的局部变量的最大区别和全局变量有点像4.154.7.1 静态存储变量static例4.15 关于静态变量 int sub( ) static int y = 0;y+;return(y); main( ) int

28、i;for(i = 0; i 5; i +) printf(“%3d”, sub(); 程序运行结果:1 2 3 4 54.7.1 静态存储变量static说明:局部的静态变量如果不对其进行初始化,系统会自动对其赋值0。虽然局部的静态变量在函数返回后依然存在,但由于它是局部变量,所以其它函数仍然不能对它进行引用。C语言规定,只有存储在静态存储区中的变量才能对其进行初始化,即,只有对全局变量和用static定义的变量才能进行自动初始化。其他类型的变量,比如局部变量必须在程序中初始化后才能使用4.7.2 动态存储变量auto®ister动态存储变量有两种:自动变量和寄存器变量1. 自动变量动

29、态存储变量是存储在动态存储区的,这种变量只在定义它们的时候才创建,在定义它们的函数返回时系统回收这些变量所占内存。对这些变量的创建和回收是由系统自动完成的,所以叫自动变量(用关键字auto定义)。关键字auto可以省略。最典型的例子就是函数中定义的局部变量和形参4.7.2 动态存储变量auto®ister2. 寄存器变量一般情况下所有的变量是存放在内存中的。如果有一个变量在某一段时间内重复使用的次数很多,如循环变量,允许将它存放在寄存器中,以提高程序的运行时间,这种变量被称为“寄存器变量”,用关键字register定义。在C程序中寄存器变量的数目也有一定的限制,只有动态变量才能作为寄存器

30、变量。4.7.3 外部存储变量extern外部变量就是在函数的外部定义的全局变量,用关键字extern来说明,它的作用域是从变量的定义开始到整个程序的结束;用extern来声明外部变量在一个文件内部声明外部变量在多个文件的程序中声明外部变量用static来声明外部变量P126 4.174.7.5 变量的生存周期变量的生存周期和变量的作用域可分为如下几类:局部变量(auto)的生存周期,从定义它的函数运行开始到函数运行结束。其作用域在定义它的函数内。静态局部变量static的生存周期,从程序的运行开始到整个程序运行结束。其作用域为定义它的函数内。4.7.5 变量的生存周期(续)全局变量exter

31、n的生存周期,从整个源程序运行开始到整个程序运行结束。其作用域为整个源程序内。静态全局变量static的生存周期,从定义它的源程序运行开始到定义它的源程序运行结束。其作用域在定义它的源程序内。只有深刻理解变量的作用域、存储类别和变量的生存周期的含义,才能写出高质量的C程序!全局和局部变量都有动态和静态两种存储方式常用的是全局变量静态存储,局部变量采用动态存储静态局部变量和静态全局变量是两个特例!static要慎用4.7.5 变量的生存周期变量的作用范围在什么范围是可以调用的,超过此范围就无法调用变量的生存周期从分配内存到内存释放生存周期和作用范围是不同的概念在生存周期内不能保障其他文件(静态全

32、局变量)或函数(静态局部变量)是可以调用的(即在作用范围内)参见谭浩强P198 表8-2 各种类型变量的作用域和存在性的情况4.8 内部函数和外部函数一个.prj工程文件可以由多个.C源文件组成但是只能有一个main()函数不同源文件文件可以访问全局变量实现变量共享一个.C源文件可以由多个函数组成不同源文件可以相互调用函数实现函数共享不同源文件之间通过互相调用函数和共享全局变量联系起来4.8 内部函数和外部函数根据函数是否能被其它源程序文件调用,又将函数分为内部函数和外部函数。4.8.1 内部函数为了防止其它源程序文件中的函数调用本源程序文件中的某些函数,在函数定义前面加上关键字“static

33、”,则称此函数为内部函数。例如:static int max(a, b); 这个max函数只能在本源文件中使用。4.8.1 内部函数举例例4.18 关于简化了的通信的例子。设置一个管理信箱的函数mail_box( ),在程序中通过send( )函数向其发信,再通过receive( )函数从信箱中接收信件。为了保证信箱的安全性,将管理信箱的函数mail_box( )、send( )函数、receive( )函数建立在一个源程序文件中,取名mail.c。4.8.1 内部函数举例 #define MAX 50 #include static void mail_box(char mail , cha

34、r p) static char mailboxMAX; if (p = s) strcpy(mailbox, mail);else if (p = r) strcpy(mail, mailbox); extern void send (char mail )mail_box(mail, s);extern void receive (char mail )mail_box(mail, r);外部函数send定义extern可省略静态局部变量内部函数4.8.1 内部函数举例 在另一个源文件mymail.c中可以这样来调用extern void send ( ) ;extern void rec

35、eive ( );main( ) char s50, r50; gets(s); send(s); receive(r); puts(r);程序运行结果:Hello!Hello!外部函数说明 不带参数4.8.2 外部函数如果函数不仅能被本源文件的函数调用,还可以被其它源文件中的函数调用,则称此函数为外部函数。外部函数定义:extern int max(a, b);extern关键字可以省略如果在源文件A中调用另一个源文件B中的函数,那么在源文件A中要调用的函数进行说明。格式:extern int max( );要区别函数定义和函数说明4.8.2 外部函数举例例4.19 外部函数的定义,说明和调

36、用文件f1.c的内容: extern void sorta(), echoa(); extern void echoa(int a ); extern int min(); main() static int a =3,8,5,1,7; echoa(a); sorta(a,5); echoa(a); printf(“The min is:%3dn”,min(a);调用外部函数的说明4.294.8.2 外部函数举例 源文件f2.c的内容如下:extern void echoa(int a ) int i; for(i=0;i5;i+) printf(“%3d”,ai); printf(“n”);函数echoa定义4.294.8.2 外部函数举例源文件f3.c的内容如下: extern void sorta(int a ,int n ) int i, j, min, t; for(i=0;in-1;i+)

温馨提示

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

评论

0/150

提交评论