




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、n教学目的教学目的n经过本章的学习,要求能熟经过本章的学习,要求能熟练掌握函数的定义和调用方法,掌练掌握函数的定义和调用方法,掌握函数的嵌套调用和递归调用,了握函数的嵌套调用和递归调用,了解变量的作用域和存储类别,掌握解变量的作用域和存储类别,掌握内部函数和外部函数,并可以在不内部函数和外部函数,并可以在不同情况下灵敏选择函数来处理实践同情况下灵敏选择函数来处理实践问题。掌握编译预处置命令的运用问题。掌握编译预处置命令的运用方法。函数和预处置命令是编写模方法。函数和预处置命令是编写模块化程序的重要方法,这将为编写块化程序的重要方法,这将为编写比较复杂的程序设计的学习打下根比较复杂的程序设计的学
2、习打下根底。底。n教学内容教学内容 函数编译预处置文件包含命令宏定义条件编译函数调用变量的作用域和存储类别内部函数和外部函数函数的定义n重点难点重点难点n 重点:重点:n (1)函数的定义和函数调用函数的定义和函数调用n (2)函数的参数传送函数的参数传送 n 难点难点n (1)函数的参数传送函数的参数传送n (2)递归调用递归调用 n (3)变量的作用域和存储特变量的作用域和存储特性性 程序员在设计一个复杂的运用程序时,往往将整个程序员在设计一个复杂的运用程序时,往往将整个程序划分为假设干个功能较为单一的程序模块,然后分程序划分为假设干个功能较为单一的程序模块,然后分别予以实现,最后将一切的
3、程序模块像积木一样装配起别予以实现,最后将一切的程序模块像积木一样装配起来,这种在程序设计中逐渐分解、分而治之的的方法,来,这种在程序设计中逐渐分解、分而治之的的方法,称之为模块化程序设计。称之为模块化程序设计。 在在C言语中,一个函数实现一个特定的功能。一个言语中,一个函数实现一个特定的功能。一个C言语程序可以由一个主函数和假设干个其它函数构成,言语程序可以由一个主函数和假设干个其它函数构成,由主函数调用其它函数,其它函数也可以相互调用。同由主函数调用其它函数,其它函数也可以相互调用。同一个函数可以被一个函数或多个函数调用恣意多次。因一个函数可以被一个函数或多个函数调用恣意多次。因此,在设计
4、时,往往将一些常用的功能模块编写成为函此,在设计时,往往将一些常用的功能模块编写成为函数,放在函数库中,供大家选用或多次调用,以减少反数,放在函数库中,供大家选用或多次调用,以减少反复性的编写程序。程序员可以方便地利用函数作为程序复性的编写程序。程序员可以方便地利用函数作为程序模块,来实现模块,来实现 C言语程序设计的模块化。言语程序设计的模块化。 在第在第1章中曾经引见过,源程序是由函数组成的。章中曾经引见过,源程序是由函数组成的。 虽虽然在前面各章的程序中都只需一个主函数然在前面各章的程序中都只需一个主函数main(), 但适但适用程序往往由多个函数组成。函数是源程序的根本模用程序往往由多
5、个函数组成。函数是源程序的根本模块,块, 经过对函数模块的调用实现特定的功能。言语中经过对函数模块的调用实现特定的功能。言语中的函数相当于其它高级言语的子程序。的函数相当于其它高级言语的子程序。 言语不仅提供言语不仅提供了极为丰富的库函数了极为丰富的库函数(如如Turbo C,MS C 都提供了三百多都提供了三百多个库函数个库函数),还允许用户建立本人定义的函数。用户可把,还允许用户建立本人定义的函数。用户可把本人的算法编成一个个相对独立的函数模块,然后用调本人的算法编成一个个相对独立的函数模块,然后用调用的方法来运用函数。用的方法来运用函数。 可以说程序的全部任务都是由各式各样的函数完成可以
6、说程序的全部任务都是由各式各样的函数完成的,的, 所以也把言语称为函数式言语。所以也把言语称为函数式言语。 由于采用了函数由于采用了函数模块式的构造,模块式的构造, 言语易于实现构造化程序设计。使程言语易于实现构造化程序设计。使程序的层次构造明晰,便于程序的编写、阅读、调试。序的层次构造明晰,便于程序的编写、阅读、调试。先举两个函数调用的简单例子。该例子引自书本配套案例先举两个函数调用的简单例子。该例子引自书本配套案例“学生成果管理学生成果管理系统系统【例【例6.1】函数调用的简单例子】函数调用的简单例子输入如下代码:输入如下代码:/*源文件名:源文件名:Li6_1.c功能:在屏幕输出显示一个
7、菜单功能:在屏幕输出显示一个菜单*/#include stdio.hvoid main()void printstart(); /*对对printstart()函数进展声明函数进展声明*/void menu(); /*对对 menu()函数进展声明函数进展声明*/printstart(); /*调用调用printstart()函数函数*/menu(); /*调用调用 menu()函数函数*/printstart(); /*调用调用printstart()函数函数*/void menu() printf(*n); printf(t1登记学生成果登记学生成果t tt2删除学生信息删除学生信息n);
8、 printf(t3查询学生信息查询学生信息t tt4修正学生资料修正学生资料n); printf(t5保管学生信息保管学生信息t tt6学生成果排序学生成果排序n);printf(t7统计学生成果统计学生成果t tt8输出学生信息输出学生信息n);printf(t0退出系统退出系统n); printf(*n); void printstart() printf(-n); 编译、衔接、运转程序。程序运转后,屏幕显示:编译、衔接、运转程序。程序运转后,屏幕显示: printstart()和和menu()都是用户定义的函数,分别用来输出一行下划都是用户定义的函数,分别用来输出一行下划线和一个菜单信
9、息。在定义这两个函数的函数时,前面加上线和一个菜单信息。在定义这两个函数的函数时,前面加上void,表示该函数无类型,也就是函数没有前往值。而函数名后面的括号表示该函数无类型,也就是函数没有前往值。而函数名后面的括号里面是空的,阐明该函数没有参数。里面是空的,阐明该函数没有参数。【例【例6.2】函数调用的简单例子】函数调用的简单例子/*源文件名:源文件名:Li6_2.c功能:求两个整数的和功能:求两个整数的和*/#include stdio.hvoid main()int sum(int x,int y); /*对对sum()函数进展声明函数进展声明*/int a,b,s;scanf(%d%d
10、,&a,&b);s=sum(a,b); /*对对sum()函数进展调用函数进展调用*/printf(the sum is %dn,s);int sum(int x,int y) /*对函数对函数sum()进展定义进展定义*/int z;/*函数体中的声明部分函数体中的声明部分*/z=x+y;return z;编译、衔接、运转程序。程序运转后,屏幕显示:编译、衔接、运转程序。程序运转后,屏幕显示:程序中程序中sum(int x,int y) 函数带有两个整型参数函数带有两个整型参数x和和y,表示,表示sum是个有是个有参函数,而在函数名前面加上参函数,而在函数名前面加上int ,
11、表示该函数会前往一个整型的数,表示该函数会前往一个整型的数值。值。 阐明:阐明: 1源程序是由函数组成的。函数是源程序的根本模块,经源程序是由函数组成的。函数是源程序的根本模块,经过对函数模块的调用实现特定的功能。言语中的函数相当于其它过对函数模块的调用实现特定的功能。言语中的函数相当于其它高级言语的子程序。言语不仅提供了极为丰富的库函数,还允许高级言语的子程序。言语不仅提供了极为丰富的库函数,还允许用户建立本人定义的函数。用户可把本人的算法编成一个个相对独用户建立本人定义的函数。用户可把本人的算法编成一个个相对独立的函数模块,然后用调用的方法来运用函数。可以说程序的全立的函数模块,然后用调用
12、的方法来运用函数。可以说程序的全部任务都是由各式各样的函数完成的,所以也把言语称为函数式部任务都是由各式各样的函数完成的,所以也把言语称为函数式言语。言语。 由于采用了函数模块式的构造,言语易于实现构造化程序设计。由于采用了函数模块式的构造,言语易于实现构造化程序设计。使程序的层次构造明晰,便于程序的编写、阅读、调试。使程序的层次构造明晰,便于程序的编写、阅读、调试。 2一个程序总是从一个程序总是从main()函数开场执行,调用其他函数后,流函数开场执行,调用其他函数后,流程回到程回到main主函数终了。主函数终了。main主函数是系统定义的,必需有且只能主函数是系统定义的,必需有且只能有一个
13、名为有一个名为main的主函数。的主函数。 3一切函数都是平行的,它们的定义都是相互独立的。一个函一切函数都是平行的,它们的定义都是相互独立的。一个函数并不从属于另外一个函数,即函数不能嵌套定义。函数间可以相数并不从属于另外一个函数,即函数不能嵌套定义。函数间可以相互调用,即函数可以嵌套调用。但不能调用互调用,即函数可以嵌套调用。但不能调用main函数,函数, main函数是函数是系统调用的。系统调用的。从函数运用的角度看,函数可分为库函数和用户定义函数两种。从函数运用的角度看,函数可分为库函数和用户定义函数两种。 1库函数:由编译系统提供的已设计好的函数,用户只需调用库函数:由编译系统提供的
14、已设计好的函数,用户只需调用而无须实现它,在编译而无须实现它,在编译 C程序时,应尽能够的运用库函数。这样可程序时,应尽能够的运用库函数。这样可以提高编程效率和编程的质量。在前面各章的例题中反复用到的以提高编程效率和编程的质量。在前面各章的例题中反复用到的printf、scanf、getchar、putchar、gets、puts、strcat等函数均属于等函数均属于库函数。库函数。 运用库函数时应留意:运用库函数时应留意: 1)函数的功能;函数的功能; 2)函数参数的数目、顺序以及每个参数的意义和类型;函数参数的数目、顺序以及每个参数的意义和类型; 3)函数前往值的意义和类型;函数前往值的意
15、义和类型; 4)需求运用的包含文件。要调用某个库函数,那么需在程序的需求运用的包含文件。要调用某个库函数,那么需在程序的头部用包含命令头部用包含命令#include将阐明该函数原型的头文件包含进本程将阐明该函数原型的头文件包含进本程序中。序中。 2用户定义函数:顾名思义,就是程序员自行定义和设计的函用户定义函数:顾名思义,就是程序员自行定义和设计的函数。库函数普通只能提供一些低层效力的功能。而用户自定义的函数。库函数普通只能提供一些低层效力的功能。而用户自定义的函数那么能针对详细的运用实现一些特殊的功能。用自定义函数需求数那么能针对详细的运用实现一些特殊的功能。用自定义函数需求程序员本人来编写
16、函数功能的实现代码。用户自定义函数是由用户程序员本人来编写函数功能的实现代码。用户自定义函数是由用户按需求写的函数。对于用户自定义函数,不仅要在程序中定义函数按需求写的函数。对于用户自定义函数,不仅要在程序中定义函数本身,而且在主调函数模块中还必需对该被调函数进展类型阐明,本身,而且在主调函数模块中还必需对该被调函数进展类型阐明,然后才干运用。然后才干运用。 言语的函数兼有其它言语中的函数和过程两种功能,从这个角言语的函数兼有其它言语中的函数和过程两种功能,从这个角度看,又可把函数分为有前往值函数和无前往值函数两种。度看,又可把函数分为有前往值函数和无前往值函数两种。 1 有前往值函数:此类函
17、数被调用执行完后将向调用者前往有前往值函数:此类函数被调用执行完后将向调用者前往一个执行结果,称为函数前往值。如数学函数即属于此类函数。由一个执行结果,称为函数前往值。如数学函数即属于此类函数。由用户定义的这种要前往函数值的函数,必需在函数定义和函数阐明用户定义的这种要前往函数值的函数,必需在函数定义和函数阐明中明确前往值的类型。中明确前往值的类型。 2 无前往值函数:此类函数用于完成某项特定的处置义务,无前往值函数:此类函数用于完成某项特定的处置义务,执行完成后不向调用者前往函数值。这类函数类似于其它言语的过执行完成后不向调用者前往函数值。这类函数类似于其它言语的过程。由于函数无须前往值,用
18、户在定义此类函数时可指定它的前往程。由于函数无须前往值,用户在定义此类函数时可指定它的前往为为“空类型,空类型, 空类型的阐明符为空类型的阐明符为“void。 定义无参函数的普通方式为:定义无参函数的普通方式为:【函数类型】【函数类型】 函数名函数名( )声明语句部分声明语句部分可执行语句部分可执行语句部分 例例6.1中的中的printstart()和和menu()函数都是无参函数。函数都是无参函数。 在定义函数时要用类型标识符来指定函数类型,即在定义函数时要用类型标识符来指定函数类型,即函数前往值的类型。如在例函数前往值的类型。如在例6.1中的中的printstart()和和menu()函数
19、的函数类型都为函数的函数类型都为void,表示不需求带回函数值。而,表示不需求带回函数值。而例例6.2中的中的sum()函数的函数类型为函数的函数类型为int,表示该函数会前,表示该函数会前往一个整型数值。往一个整型数值。 留意:在函数类型缺省的情况下,系一致概按留意:在函数类型缺省的情况下,系一致概按int型型处置。处置。 定义有参函数的普通方式为:定义有参函数的普通方式为:【函数类型】【函数类型】 函数名函数名( 数据类型数据类型 参数【,数据类参数【,数据类型型 参数参数2】)声明语句部分声明语句部分可执行语句部分可执行语句部分例例6.2中的中的sum(int x,int y)就是一个有
20、参函数。就是一个有参函数。详细分析一下详细分析一下sum函数:函数:int sum(int x,int y)/*对函数对函数sum()进展定义进展定义*/int z;/*函数体中的声明部分函数体中的声明部分*/z=x+y;return z; 这是一个求两个整型数据之和的函数。第一行中的这是一个求两个整型数据之和的函数。第一行中的int 表示函数前表示函数前往值是整型的,往值是整型的,sum为函数名,括号中的两个方式参数为函数名,括号中的两个方式参数x和和y都是整都是整型的。在调用该函数的时候,主调函数把实践参数的值传送给被调型的。在调用该函数的时候,主调函数把实践参数的值传送给被调用函数中的方
21、式参数用函数中的方式参数x和和y。大括号内是函数体,经过函数体中语句。大括号内是函数体,经过函数体中语句的执行求出的执行求出x和和y的和,经过的和,经过return z;语句把;语句把z作为函数值前往到主作为函数值前往到主调函数中。调函数中。return后面的后面的z也称为函数前往值。也称为函数前往值。 留意:普通情况下,函数前往值的类型和函数类型是一致的。假留意:普通情况下,函数前往值的类型和函数类型是一致的。假设不一致,那么以函数类型为准。设不一致,那么以函数类型为准。 一个较大的程序普通应分为假设干个程序模块,每一个模块用来一个较大的程序普通应分为假设干个程序模块,每一个模块用来实现一个
22、特定的功能。而在第一个阶段只设计最根本的模块,功能实现一个特定的功能。而在第一个阶段只设计最根本的模块,功能可以在设计好框架以后渐渐补上。在编写程序的开场阶段,往往是可以在设计好框架以后渐渐补上。在编写程序的开场阶段,往往是先写上一个空函数,占个位置,以后再用编写好的函数来交换它。先写上一个空函数,占个位置,以后再用编写好的函数来交换它。这样,程序的构造比较清楚,可读性比较好,以后扩展新功能也比这样,程序的构造比较清楚,可读性比较好,以后扩展新功能也比较方便,对程序构造影响不大。在程序设计中空函数经常被运用到,较方便,对程序构造影响不大。在程序设计中空函数经常被运用到,它的定义方式为:它的定义
23、方式为:【函数类型】【函数类型】 函数名函数名()例如,在设计一个学生成果管理系统的开场阶段,可以运用空函数例如,在设计一个学生成果管理系统的开场阶段,可以运用空函数设计如下的程序框架设计如下的程序框架 void main()void addscore() /*addscore()函数实现成果的添加函数实现成果的添加*/ void alterscore() /*alterscore()函数实现成果的修正函数实现成果的修正*/ void deletescore() /*deletescore()函数实现成果的删除函数实现成果的删除*/ 之后编写程序的时候,在设计好的框架上完善就可以了。之后编写程
24、序的时候,在设计好的框架上完善就可以了。 函数的参数分为形参和实参两种。形参出如今函数函数的参数分为形参和实参两种。形参出如今函数定义中,在整个函数体内都可以运用,分开该函数那么定义中,在整个函数体内都可以运用,分开该函数那么不能运用。实参出如今主调函数中,进入被调函数后,不能运用。实参出如今主调函数中,进入被调函数后,实参变量也不能运用。形参和实参的功能是作数据传送。实参变量也不能运用。形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。的形参从而实现主调函数向被调函数的数据
25、传送。 函数的形参和实参具有以下特点:函数的形参和实参具有以下特点: 1.形参变量只需在被调用时才分配内存单元,在调用终了时,形参变量只需在被调用时才分配内存单元,在调用终了时,所分配的内存单元也将被释放。因此,形参只需在函数内部有效。所分配的内存单元也将被释放。因此,形参只需在函数内部有效。函数调用终了前往主调函数后那么不能再运用该形参变量。函数调用终了前往主调函数后那么不能再运用该形参变量。 2.实参可以是常量、变量、表达式、函数等,无论实参是何种实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进展函数调用时,它们都必需具有确定的值,以便把类型的量,在进展函数调用时,它们都
26、必需具有确定的值,以便把这些值传送给形参。因此应预先用赋值、输入等方法使实参获得确这些值传送给形参。因此应预先用赋值、输入等方法使实参获得确定值。定值。 3.实参和形参在数量、类型、顺序上应严厉一致,否那么会发实参和形参在数量、类型、顺序上应严厉一致,否那么会发生类型不匹配的错误。生类型不匹配的错误。 4.函数调用中发生的数据传送是单向的。即只能把实参的值传函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用因此在函数调用过程中,形参的值发生改动,而实参中的值不会变化。过程中,形参的值发生改
27、动,而实参中的值不会变化。 函数的前往值是指函数被调用之后,执行函数体中的程序段所获得的并经函数的前往值是指函数被调用之后,执行函数体中的程序段所获得的并经过过return语句前往给主调函数的值。如调用语句前往给主调函数的值。如调用sqrt()函数获得开根号的值,调函数获得开根号的值,调用例用例6.2的的sum函数获得的两数之和等。对函数的前往值函数获得的两数之和等。对函数的前往值 (或称函数的值或称函数的值)有以有以下一些阐明:下一些阐明: 1.函数的值只能经过函数的值只能经过return语句前往主调函数。语句前往主调函数。return 语句的普通方式为:语句的普通方式为:return 表达
28、式;表达式;或者为:或者为:return (表达式表达式); 该语句的功能是计算表达式的值,并前往给主调函数。在函数中允许有多该语句的功能是计算表达式的值,并前往给主调函数。在函数中允许有多个个return语句,但每次调用只能有一个语句,但每次调用只能有一个return 语句被执行,因此一个函数最语句被执行,因此一个函数最多只能前往一个函数值。多只能前往一个函数值。 例如:例如:signint x ifx0 return1; ifx=0 return0; ifx b) c=1;else if(a=b) c=0;else c=-1;return c; 编译、衔接、运转程序。程序运转后,屏幕显示:
29、编译、衔接、运转程序。程序运转后,屏幕显示: 假设按自左向右顺序务虚参的值,那么函数调用相当于假设按自左向右顺序务虚参的值,那么函数调用相当于compare(2,3),程序运转的结果应为程序运转的结果应为-1。假设按自右向左顺序务虚。假设按自右向左顺序务虚参的值,那么相当于参的值,那么相当于compare(3,3),程序运转结果为程序运转结果为0。假设不清。假设不清楚本人所用的编译器对实参的求值顺序,用上述代码上机一试就清楚本人所用的编译器对实参的求值顺序,用上述代码上机一试就清楚了。楚了。 留意:由于不同的编译器对实参的求值顺序不一样,为了使程留意:由于不同的编译器对实参的求值顺序不一样,为
30、了使程序的通用性不受影响以及防止大家对同一段代码产生不同的了解,序的通用性不受影响以及防止大家对同一段代码产生不同的了解,应尽量防止运用这种容易混淆的用法。应尽量防止运用这种容易混淆的用法。按函数在程序中出现的位置来分,可以有一下三种函数调用的方式。按函数在程序中出现的位置来分,可以有一下三种函数调用的方式。1.函数语句函数语句把函数调用作为一个语句。如例把函数调用作为一个语句。如例6.1中的中的printstart();这时不要求函数带前往这时不要求函数带前往值,只需求函数完成一些操作。值,只需求函数完成一些操作。2.函数表达式函数表达式函数出如今一个表达式中,这种表达式称为函数表达式。这时
31、要求函数带回函数出如今一个表达式中,这种表达式称为函数表达式。这时要求函数带回一个确定的值以参与表达式的运算。例如:一个确定的值以参与表达式的运算。例如:s=sum(a,b)+sum(x,y);函数函数sum是表达式的一部分,将是表达式的一部分,将sum(a,b)的值加上的值加上sum(x,y)的和赋值给的和赋值给s。3.函数参数函数参数函数调用作为一个函数的参数,例如:函数调用作为一个函数的参数,例如:s=sum(a,sum(b,c);其中,其中,sum(b,c)是一次函数调用,它的值作为是一次函数调用,它的值作为sum另一次调用的参数。另一次调用的参数。s的值的值为为a,b,c三数的总和。
32、三数的总和。其实,函数调用作为函数的参数,也是函数表达式调用的一种方式,由于函其实,函数调用作为函数的参数,也是函数表达式调用的一种方式,由于函数参数本身就是一个表达式的方式。数参数本身就是一个表达式的方式。假设一个函数要调用另外一个函数,首先是被调用的函数必需存在。假设一个函数要调用另外一个函数,首先是被调用的函数必需存在。其次还应在主调函数中对一切被调函数加以阐明,否那么,在衔接其次还应在主调函数中对一切被调函数加以阐明,否那么,在衔接时会出现找不到所调用函数的错误信息。同变量一样,函数的调用时会出现找不到所调用函数的错误信息。同变量一样,函数的调用也应遵照也应遵照“先定义后运用的原那么。
33、先定义后运用的原那么。 对被调函数的声明分为两种情况:对被调函数的声明分为两种情况:1假设被调函数是假设被调函数是C言语系统提供的规范库函数,那么在源程序言语系统提供的规范库函数,那么在源程序文件的开头处,运用文件的开头处,运用#include命令,将存放所调用库函数的有关命令,将存放所调用库函数的有关“头头文件包含到该程序文件中来。文件包含到该程序文件中来。 #include命令的普通方式为:命令的普通方式为: #include或或#include stdio.h2假设被调用函数为用户本人定义的函数,普通情况下,应在主假设被调用函数为用户本人定义的函数,普通情况下,应在主调函数中对被调用函数
34、前往值的类型进展阐明。函数的阐明方调函数中对被调用函数前往值的类型进展阐明。函数的阐明方法是:在主调函数的声明部分对被调函数进展声明。在主调函数中法是:在主调函数的声明部分对被调函数进展声明。在主调函数中对被调函数作阐明的目的是使编译系统知道被调函数前往值的类型,对被调函数作阐明的目的是使编译系统知道被调函数前往值的类型,以便在主调函数中按此种类型对前往值作相应的处置。以便在主调函数中按此种类型对前往值作相应的处置。其普通方式为:其普通方式为: 类型阐明符类型阐明符 被调函数名被调函数名(类型类型 形参,类型形参,类型 形参形参); 或者:或者: 类型阐明符类型阐明符 被调函数名被调函数名(类
35、型,类型类型,类型); 括号内给出了形参的类型和形参名,或只给出形参类型。这便于编括号内给出了形参的类型和形参名,或只给出形参类型。这便于编译系统进展检错,以防止能够出现的错误。译系统进展检错,以防止能够出现的错误。例例6.1 main函数对函数对printstart()函数的阐明为:函数的阐明为:void printstart();例例6.2 main函数对函数对sum()函数的阐明为:函数的阐明为:int sum(int x,int y);也可以写成:也可以写成:int sum(int ,int);言语中规定在以下几种情况时可以省去在主调函数中对被调函数言语中规定在以下几种情况时可以省去在
36、主调函数中对被调函数的函数阐明。的函数阐明。1)当被调函数的前往值是整型或字符型时,可以不对被调函数当被调函数的前往值是整型或字符型时,可以不对被调函数作阐明。这时系统会自动对被调函数前往值按整型处置。例作阐明。这时系统会自动对被调函数前往值按整型处置。例6.3的主的主函数中把函数声明语句函数中把函数声明语句int compare(int a,int b);注释掉而直接调用就注释掉而直接调用就属于这种情况。属于这种情况。2)当被调函数的函数定义出如今主调函数之前时,在主调函数当被调函数的函数定义出如今主调函数之前时,在主调函数中也可以不对被调函数再作阐明而直接调用。例如例中也可以不对被调函数再
37、作阐明而直接调用。例如例6.1中,函数中,函数printstart()的定义放在的定义放在 menu() 函数之前,因此可在函数之前,因此可在 menu()函数中省函数中省去对去对printstart()函数的函数阐明函数的函数阐明void printstart();3)如在一切函数定义之前,在函数外预先阐明了各个函数的类如在一切函数定义之前,在函数外预先阐明了各个函数的类型,那么在以后的各主调函数中,可以不再对被调函数作阐明。型,那么在以后的各主调函数中,可以不再对被调函数作阐明。例如:例如: long factor (int a); long sum(int b); void main()
38、 long factor (int a) long sum(int b) 其中第一、二行对其中第一、二行对factor函数和函数和sum函数预先作了阐明。因此在以后各函数函数预先作了阐明。因此在以后各函数中无须对中无须对factor和和sum函数再作阐明就可直接调用。函数再作阐明就可直接调用。【例【例6.4】计算】计算 = 1!+2!+ + n!(n1,20的整数,从键盘输入的整数,从键盘输入)。算法设计要点:算法设计要点:本案例可以设计本案例可以设计2个函数:个函数:factor( )用于求用于求n!;!;sum( )经过调用经过调用factor( )来实现求来实现求。输入如下代码:输入如下
39、代码:/*源文件名:源文件名:Li6_4.c功能:求阶乘和功能:求阶乘和 */#include stdio.hlong factor(int n)/*定义求阶乘函数定义求阶乘函数factor()*/int i;long f=1;for(i=1;i=n;i+)f=f*i;return f;long sum(int m)/*定义求和函数定义求和函数sum()*/int i;long s=0;for(i=1;i1)f=n*factor(n-1);else f=1;return f;void main()int n;long s;printf(please input a number:);scanf
40、(%d,&n);s=factor(n);/*调用调用factor()函数函数*/printf(%d!=%ldn,n,s);编译、衔接、运转程序。程序运转后,屏幕显示:编译、衔接、运转程序。程序运转后,屏幕显示:其中,其中,factor函数在定义的过程中调用了本身,这种情况叫做函数的函数在定义的过程中调用了本身,这种情况叫做函数的递归调用。递归调用。 一个函数在它的函数体内调用它本身称为递归调用。这种函数称为递归函一个函数在它的函数体内调用它本身称为递归调用。这种函数称为递归函数。言语允许函数的递归调用。在递归调用中,主调函数又是被调函数。数。言语允许函数的递归调用。在递归调用中,主调函
41、数又是被调函数。执行递归函数将反复调用其本身,每调用一次就进入新的一层。执行递归函数将反复调用其本身,每调用一次就进入新的一层。 下面以例下面以例6.5阐明一下递归的执行过程。阐明一下递归的执行过程。 设执行本程序时输入为设执行本程序时输入为5,即求,即求5!。在主函数中的调用语句即为。在主函数中的调用语句即为s=factor(5);,进入,进入factor函数后,由于函数后,由于n=5,大于大于1,故应执行,故应执行f=n*factor(n*1),即即f=factor(5-1)*5。该语句对。该语句对factor函数作递归调用即函数作递归调用即factor(4)。 进展四次递归调用后,进展四
42、次递归调用后,factor函数形参获得的值变为函数形参获得的值变为1,故不再继续递归调,故不再继续递归调用而开场逐层前往主调函数。用而开场逐层前往主调函数。factor(1)的函数前往值为的函数前往值为1,factor(2)的前往值的前往值为为2*1=2,factor(3)的前往值为的前往值为3*2=6,factor(4)的前往值为的前往值为4*6=24,最后前,最后前往值往值factor(5)为为5*24=120。 留意:为了防止递归调用无终止地进展,必需在函数内有终止递归调用的留意:为了防止递归调用无终止地进展,必需在函数内有终止递归调用的手段。常用的方法是加条件对递归能否继续进展判别,满
43、足某种条件后就不手段。常用的方法是加条件对递归能否继续进展判别,满足某种条件后就不再作递归调用,而是逐层前往。如例再作递归调用,而是逐层前往。如例6.5中的条件中的条件if(n1)就是控制递归继续就是控制递归继续的条件,当的条件,当n不小于不小于1的时候递归就终止,开场回朔的过程。的时候递归就终止,开场回朔的过程。 一个函数假设只能被本文件中其它函数所调用,称一个函数假设只能被本文件中其它函数所调用,称为内部函数,内部函数又称静态函数。在定义内部函数为内部函数,内部函数又称静态函数。在定义内部函数时在函数名和函数类型前面加时在函数名和函数类型前面加static。即:。即: static 函数类
44、型函数类型 函数名形参列表函数名形参列表 函数体函数体 例:例:static int fun(int a,int b) 特点:只能被本文件中的函数所调用。特点:只能被本文件中的函数所调用。 优点:不用担忧与其它源文件中的函数同名,由于优点:不用担忧与其它源文件中的函数同名,由于即使同名也没关系。即使同名也没关系。一个函数可以被其它文件中其它函数所调用,就称为外一个函数可以被其它文件中其它函数所调用,就称为外部函数。在定义函数时可冠以关键字部函数。在定义函数时可冠以关键字extern省略也可,省略也可,表示此函数是外部函数。即:表示此函数是外部函数。即:extern 函数类型函数类型 函数名形参
45、列表函数名形参列表函数体函数体如:如:extern int fun(int a,int b)特点:允许被一切源文件中的函数所调用。特点:允许被一切源文件中的函数所调用。留意:调用其它源文件中的外部函数时,需求对其进展留意:调用其它源文件中的外部函数时,需求对其进展阐明。阐明。 【例【例6.6】以多文件的方式实现加、减、乘、除和求余】以多文件的方式实现加、减、乘、除和求余数运算程序数运算程序 阐明:将实现加、减、乘、除和求余数运算的程序段阐明:将实现加、减、乘、除和求余数运算的程序段分别作为分别作为1个独立的函数、存储在个独立的函数、存储在1个独立的源文件中。个独立的源文件中。 程序框架如下程序
46、框架如下(完好程序详见【例完好程序详见【例6.6】源代码】源代码): 分别创建分别创建addition.c源文件、源文件、subtraction.c源文件、源文件、multiplication.c源文件、源文件、division.c源文件、源文件、remainder.c源源文件,分别在各源文件中实现相应的加、减、乘、除和文件,分别在各源文件中实现相应的加、减、乘、除和求余数函数的功能。求余数函数的功能。编译、衔接、运转程序。程序运转后,屏幕显示:编译、衔接、运转程序。程序运转后,屏幕显示: 在软件工程工程中,采用构造化方法进展程序设计与编程,通常在软件工程工程中,采用构造化方法进展程序设计与编
47、程,通常会产生多个源文件例如源程序文件、数据构造定义文件等。会产生多个源文件例如源程序文件、数据构造定义文件等。 那么,如何将这些源文件编译、衔接成一个一致的可执行文件呢?那么,如何将这些源文件编译、衔接成一个一致的可执行文件呢? 普通有两种方法:普通有两种方法: 1. 分别编译、一并衔接分别编译、一并衔接 C编译程序是以源文件为编译单位。编译程序是以源文件为编译单位。 当一个程序中的函数和数据构造分放在多个源文件中时,先将各当一个程序中的函数和数据构造分放在多个源文件中时,先将各文件分别编译,再经过文件分别编译,再经过link命令产生一个可执行文件命令产生一个可执行文件(.exe) 。 2.
48、 集中编译、衔接集中编译、衔接 利用编译预处置命令利用编译预处置命令#include,将其它源文件包含到主函数,将其它源文件包含到主函数main( )所在的源文件的开头,然后直接编译该文件即可。所在的源文件的开头,然后直接编译该文件即可。 【例【例6.7】先经过添加源文件的操作将】先经过添加源文件的操作将addition.c源文件,源文件,subtraction.c源文件,源文件,multiplication.c源文件,源文件,division.c源文件,源文件,remainder.c源文件添加到本工程加减乘除求余来,然后在其主源文件添加到本工程加减乘除求余来,然后在其主函数函数main()里
49、添加如下几行:里添加如下几行:/*源文件名:源文件名:Li6_7.c功能:以多文件的方式实现加、减、乘、除和求余数运算功能:以多文件的方式实现加、减、乘、除和求余数运算*/*将其它各源文件包含进来将其它各源文件包含进来*/#include addition.c#include subtraction.c#include multiplication.c#include division.c#include remainder.c void main( ) 部分变量也称为内部变量。部分变量是在函数内包括函数阐部分变量也称为内部变量。部分变量是在函数内包括函数阐明和函数体作定义阐明的,其作用域仅限
50、于函数内,明和函数体作定义阐明的,其作用域仅限于函数内, 分开该函数分开该函数后再运用这种变量是非法的。后再运用这种变量是非法的。 【例【例6.8】部分变量的作用域】部分变量的作用域 输入如下代码:输入如下代码: /*源文件名:源文件名:Li6_8.c功能:测试部分变量的作用域功能:测试部分变量的作用域 */ #include stdio.h void test(int a) int b=20;printf(%dn,a+b); void main() int i=2,j=3,k; k=i+j; int k=8; printf(%dn,k); printf(%dn,k);test(k);编译、衔
51、接、运转程序。程序运转后,屏幕显示:编译、衔接、运转程序。程序运转后,屏幕显示: 在函数在函数test内定义了三个变量,内定义了三个变量,a为形参,为形参,b为普通变量。在为普通变量。在 test的范围内的范围内a、b有效,或者说有效,或者说a、b变量的作用域限于变量的作用域限于test内。同理,内。同理,i,j,k的作用域限于的作用域限于main内。内。 关于部分变量的作用域还要阐明以下几点:关于部分变量的作用域还要阐明以下几点: 1) 主函数中定义的变量只能在主函数中运用,不主函数中定义的变量只能在主函数中运用,不能在其它函数中运用。同时,主函数中也不能运用其它能在其它函数中运用。同时,主
52、函数中也不能运用其它函数中定义的变量。由于主函数也是一个函数,它与其函数中定义的变量。由于主函数也是一个函数,它与其它函数是平行关系。这一点是与其它言语不同的,应予它函数是平行关系。这一点是与其它言语不同的,应予以留意。以留意。 2) 形参变量是属于被调函数的部分变量,实参变形参变量是属于被调函数的部分变量,实参变量是属于主调函数的部分变量。量是属于主调函数的部分变量。 3) 允许在不同的函数中运用一样的变量名,它们允许在不同的函数中运用一样的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。发生混淆。 4) 在复合语句中也可
53、定义变量,其作用域只在复在复合语句中也可定义变量,其作用域只在复合语句范围内。合语句范围内。 全局变量也称为外部变量,它是在函数外部定义的变全局变量也称为外部变量,它是在函数外部定义的变量。它不属于哪一个函数,它属于整个源程序文件。其量。它不属于哪一个函数,它属于整个源程序文件。其作用域是整个源程序。在函数中运用全局变量,普通应作用域是整个源程序。在函数中运用全局变量,普通应作全局变量阐明。作全局变量阐明。 只需在函数内经过阐明的全局变量才干运用。全局变只需在函数内经过阐明的全局变量才干运用。全局变量的阐明符为量的阐明符为extern。但在一个函数之前定义的全局变量,。但在一个函数之前定义的全
54、局变量,在该函数内运用可不再加以阐明。在该函数内运用可不再加以阐明。【例【例6.9】要求设计一个函数】要求设计一个函数cuboiddouble length, double width, double height3个参数依次为长方体的长、宽、高,用于求长个参数依次为长方体的长、宽、高,用于求长方体的体积及正、侧、顶三个面的面积。方体的体积及正、侧、顶三个面的面积。算法设计要点:算法设计要点:函数函数cuboid (int length, int width, int height)本身只能前往本身只能前往1个值本个值本案例选定体积,正、侧、顶三个面的面积就只能经过外部变量来案例选定体积,正、
55、侧、顶三个面的面积就只能经过外部变量来进展数据共享。进展数据共享。 /*源文件名:源文件名:Li6_9.c功能:求长方体的体积及正、侧、顶三个面的面积功能:求长方体的体积及正、侧、顶三个面的面积 */#include stdio.hdouble area1, area2, area3;/*定义定义3个外部变量,用于数据共享个外部变量,用于数据共享*/double cuboid (double length, double width, double height);/*函数阐明函数阐明*/void main( )double volume,length,width,height; printf
56、(please input the cuboids length、width and height:);scanf(%lf%lf%lf,&length,&width,&height);volume = cuboid (length, width, height);printf(n volume = %.2lf, area1 = %.2lf, area2 = %.2lf, area3 = %.2lfn , volume, area1, area2, area3);double cuboid (double length, double width, double heig
57、ht)double volume;volume = length * width * height;/*计算体积计算体积*/area1= length * width; /*计算计算3个面的面积个面的面积*/area2= width * height; area3= length * height;return( volume);/*前往体积值前往体积值*/编译、衔接、运转程序。程序运转后,屏幕显示:编译、衔接、运转程序。程序运转后,屏幕显示:留意:留意:(1)外部变量的作用域:从定义点到本文件终了。外部变量的作用域:从定义点到本文件终了。为方便运用,建议将外部变量的定义放在文件开头,如例为方
58、便运用,建议将外部变量的定义放在文件开头,如例6.9所示。所示。(2)在同一源文件中,允许外部变量和内部变量同名。在同一源文件中,允许外部变量和内部变量同名。在内部变量的作用域内,外部变量不起作用。在内部变量的作用域内,外部变量不起作用。(3)外部变量可实现函数之间的数据共享,但又使这些函数依赖这些外部变量可实现函数之间的数据共享,但又使这些函数依赖这些外部变量,因此使得这些函数的独立性降低。外部变量,因此使得这些函数的独立性降低。从模块化程序设计观念来看,这是不利的。因此不是非用不可时,从模块化程序设计观念来看,这是不利的。因此不是非用不可时,不要运用外部变量。不要运用外部变量。 言语中的变
59、量,不仅有类型特性,还有存储特性,从变量值言语中的变量,不仅有类型特性,还有存储特性,从变量值存在的时间即生存期角度来分,可以分为静态存储方式和动态存在的时间即生存期角度来分,可以分为静态存储方式和动态存储方式。存储方式。 1动态存储方式:是在程序运转期间根据需求进展动态的分配动态存储方式:是在程序运转期间根据需求进展动态的分配存储空间的方式。存储空间的方式。自动内部变量自动内部变量(auto)、存放器变量、存放器变量(register) 2静态存储方式:是指在程序运转期间分配固定的存储空间的静态存储方式:是指在程序运转期间分配固定的存储空间的方式。静态内部变量方式。静态内部变量(static
60、)、外部变量、外部变量(extern) 。用户存储空间可以分为三个部分:用户存储空间可以分为三个部分: (1) 程序区;程序区; (2) 静态存储区;静态存储区; (3) 动态存储区;动态存储区; 全局变量全部存放在静态存储区,在程序开场执行时给全局变全局变量全部存放在静态存储区,在程序开场执行时给全局变量分配存储区,程序运转终了就释放。在程序执行过程中它们占据量分配存储区,程序运转终了就释放。在程序执行过程中它们占据固定的存储单元,而不动态地进展分配和释放;固定的存储单元,而不动态地进展分配和释放;动态存储区存放以下数据:动态存储区存放以下数据: 1) 函数方式参数;函数方式参数; 2) 自动变量未加自动变量未加static声明的部分
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年山东省东营市八年级中考二模生物试题(含答案)
- 2025年医用冰箱市场分析现状
- 2025届江苏省镇江新区大港中学七年级生物第二学期期末综合测试模拟试题含解析
- 2025届山东省沂水县生物七下期末检测模拟试题含解析
- 2025届四川省南充市西南石油院附属学校生物七下期末联考试题含解析
- 安全教育主题班会课件教学
- 安全度夏培训课件
- 安全培训课件百度网盘
- 无形资产及其他资产在课件创作中的作用教学
- 2025年文化品牌建设的管理实践试题及答案
- (完整版)CAD考试试题库及参考答案
- 信息技术系统故障应急恢复方案及保障措施
- 大数据算法学习通超星期末考试答案章节答案2024年
- DB11T 3034-2023 建筑消防设施检测服务规范
- 激光武器(原创完整)课件
- 2023-2024年全国初中化学竞赛试卷及答案
- 中医内科学-痹证
- 2024图书馆领域大模型创新应用需求调研报告V0-WN8正式版
- GB/T 10069.3-2024旋转电机噪声测定方法及限值第3部分:噪声限值
- 网络安全宣传周网络安全知识手册学习课件
- 2024年公文写作基础知识竞赛试题库及答案(共220题)
评论
0/150
提交评论