版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、本章要点 8.1 8.1 概述概述 8. 8.函数定义的一般形式函数定义的一般形式 8. 8.函数参数和函数的值函数参数和函数的值 8. 8. 函数的调用函数的调用 8. 8. 函数的嵌套调用函数的嵌套调用 8. 8.函数的递归调用函数的递归调用 8. 8.数组作为函数参数数组作为函数参数 8.8 8.8 局部变量和全局变量局部变量和全局变量 8. 8.变量的存储类别变量的存储类别 8.10 8.10 内部函数和外部函数内部函数和外部函数一个较大的程序可分为若干个程序模块程序模块,每一个模块用来实现一个特定的功能。在高级语言中用子程序子程序实现模块的功能。子程序由函数来完成。一个程序可由一个主
2、函数和若干个其他函数构成。由主函数调用其他函数,其他函数也可以互相调用。由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函数调用任意多次。同一个函数可以被一个或多个函数调用任意多次。函数间的调用关系函数间的调用关系# include void main() void printstar(); /*对对printstar函数声明函数声明*/ void print_message(); /*对对print_message函数声明函数声明*/ printstar(); *调用调用printstar函数函数* print_message(); /*调用调用print_messa
3、ge函数函数*/ printstar(); *调用调用printstar函数函数*/ 例例8.18.1void printstar() *定义定义printstar函数函数* printf(* * * * * * * * * * * * * * * *n);void print_message() *定义定义print_message函数函数* printf(how do you do!n); 运行情况如下:运行情况如下:* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *how do you do!how do you
4、 do!* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *(1 1)一个程序由一个或多个程序模块组成,一个程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对较每一个程序模块作为一个源程序文件。对较大的程序,一般不希望把所有内容全放在一大的程序,一般不希望把所有内容全放在一个文件中,而是将他们分别放在若干个源文个文件中,而是将他们分别放在若干个源文件中,再由若干源程序文件组成一个件中,再由若干源程序文件组成一个c程序。程序。这样便于分别编写、分别编译,提高调试效这样便于分别编写、分别编译,提高调试效率。一
5、个源程序文件可以为多个率。一个源程序文件可以为多个c程序公用。程序公用。(2 2) 一个源程序文件由一个或多个函数以及一个源程序文件由一个或多个函数以及其他有关内容(如命令行、数据定义等)组成其他有关内容(如命令行、数据定义等)组成。一个源程序文件是一个编译单位,在程序编。一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位进行编译的,而不译时是以源程序文件为单位进行编译的,而不是以函数为单位进行编译的。是以函数为单位进行编译的。 (3 3)程序的执行是从函数开始的程序的执行是从函数开始的,如是在函数中调用其他函数,在调,如是在函数中调用其他函数,在调用后流程返回到函数,在函用后流程
6、返回到函数,在函数中结束整个程序的运行。数中结束整个程序的运行。 (4 4) 所有函数都是平行的,即在定义函数时所有函数都是平行的,即在定义函数时是分别进行的,是互相独立的。一个函数并不是分别进行的,是互相独立的。一个函数并不从属于另一函数,即函数不能嵌套定义。函数从属于另一函数,即函数不能嵌套定义。函数间可以互相调用,但不能调用函数。间可以互相调用,但不能调用函数。函数是系统调用的。函数是系统调用的。 (5 5)从用户使用的角度看,函数有两种:从用户使用的角度看,函数有两种: 标准函数,即库函数。这是由系统提供的标准函数,即库函数。这是由系统提供的,用户不必自己定义这些函数,可以直接使,用户
7、不必自己定义这些函数,可以直接使用它们。应该说明,不同的用它们。应该说明,不同的c系统提供的库系统提供的库函数的数量和功能会有一些不同,当然许多函数的数量和功能会有一些不同,当然许多基本的函数是共同的。基本的函数是共同的。 用户自己定义的函数。用以解决用户的专用户自己定义的函数。用以解决用户的专门需要。门需要。 (6 6) 从函数的形式看,函数分两类:从函数的形式看,函数分两类: 无参函数。如例无参函数。如例8.18.1中的中的printstarprintstar和和print_messageprint_message就是无参函数。在调用无参函就是无参函数。在调用无参函数时,主调函数不向被调用
8、函数传递数据。无数时,主调函数不向被调用函数传递数据。无参函数一般用来执行指定的一组操作。例如,参函数一般用来执行指定的一组操作。例如,例例8 8程序中的程序中的printstarprintstar函数。函数。有参函数。在调用函数时,主调函数在调用有参函数。在调用函数时,主调函数在调用被调用函数时,通过参数向被调用函数传递数被调用函数时,通过参数向被调用函数传递数据,一般情况下,执行被调用函数时会得到一据,一般情况下,执行被调用函数时会得到一个函数值,供主调函数使用。个函数值,供主调函数使用。 定义定义无参函数无参函数的一般形式为的一般形式为: :类型标识符类型标识符函数名函数名()() 声明
9、部分声明部分 语句部分语句部分 在定义函数时要在定义函数时要用用“类型标识符类型标识符”指定函数值的类指定函数值的类型,即函数带回型,即函数带回来的值的类型。来的值的类型。例例8.8.中的中的printstarprintstar和和print_messageprint_message函函数为数为voidvoid类型,类型,表示不需要带回表示不需要带回函数值。函数值。 定义定义有参函数有参函数的一般形式为的一般形式为: :类型标识符类型标识符函数名函数名(形式参数表列)(形式参数表列) 声明部分声明部分 语句部分语句部分 例如:例如: (intint ,intint ) ;/ / * *函数体中
10、的声明部分函数体中的声明部分* * ?; ();(); 定义定义空函数空函数的一般形式为的一般形式为: :类型标识符类型标识符函数名函数名()() 例如:例如:()() 调用此函数时,什么调用此函数时,什么工作也不做,没有任工作也不做,没有任何实际作用。在主调何实际作用。在主调函数中写上函数中写上“();();”表明表明“这里要调用一个函这里要调用一个函数数”,而现在这个函,而现在这个函数没有起作用,等以数没有起作用,等以后扩充函数功能时补后扩充函数功能时补充上。充上。 大多数情况下,主调函数和被调用函数之间有大多数情况下,主调函数和被调用函数之间有数据传递的关系。数据传递的关系。在不同的函数
11、之间传递数据,可以使用的方在不同的函数之间传递数据,可以使用的方 法:法:参数:通过形式参数和实际参数参数:通过形式参数和实际参数返回值返回值:用:用returnreturn语句返回计算结果语句返回计算结果全局变量:外部变量全局变量:外部变量#include stdio.h#include void void ()() int max(intint max(int ,intint ) ); / /* * 对函数的声明对函数的声明 * */ / int int ,;,; scanfscanf(,);(,); (,);(,); printfprintf( ,);,); 例例8.8.调用函数时的数据
12、传递调用函数时的数据传递 int max(intint max(int ,intint ) )* *定义有参函数定义有参函数max max * * intint ; ?; returnreturn();(); 运行情况如下:, 通过函数调用,使两个函数中的数据发生联系通过函数调用,使两个函数中的数据发生联系 关于形参与实参的说明:关于形参与实参的说明:(1) 在定义函数中指定的形参,在未出现函数在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。只有调用时,它们并不占内存中的存储单元。只有在发生函数调用时,函数中的形参才被在发生函数调用时,函数中的形参才被分配内存单元。在调
13、用结束后,形参所占的内分配内存单元。在调用结束后,形参所占的内存单元也被释放。存单元也被释放。(2) (2) 实参可以是常量、变量或表达式,如:实参可以是常量、变量或表达式,如: (,);(,);但要求它们有确定的值。在调用时将实参的值但要求它们有确定的值。在调用时将实参的值赋给形参。赋给形参。(3) (3) 在被定义的函数中,必须指定形参的类在被定义的函数中,必须指定形参的类型(见例型(见例8.28.2程序中的程序中的 “(,(,););” )。)。(4) (4) 实参与形参的类型应相同或赋值兼容。实参与形参的类型应相同或赋值兼容。例例8 8中实参和形参都是整型。如果实参为中实参和形参都是整
14、型。如果实参为整型而形参整型而形参x x为实型,或者相反,则按第为实型,或者相反,则按第3 3章章介绍的不同类型数值的赋值规则进行转换。介绍的不同类型数值的赋值规则进行转换。例如实参值例如实参值a a为为3.53.5,而形参,而形参x x为整型,则将为整型,则将实数实数3.53.5转换成整数转换成整数3 3,然后送到形参,然后送到形参b b。字。字符型与整型可以互相通用。符型与整型可以互相通用。(5) (5) 在语言中,实参向对形参的数据传递在语言中,实参向对形参的数据传递是是“值传递值传递”,单向传递,只由实参传给形,单向传递,只由实参传给形参,而不能由形参传回来给实参。在内存中,参,而不能
15、由形参传回来给实参。在内存中,实参单元与形参单元是不同的单元。实参单元与形参单元是不同的单元。 在调用函数时,给形参分配存储单元,并将实在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。因此,元被释放,实参单元仍保留并维持原值。因此,在执行一个被调用函数时,形参的值如果发生在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数的实参的值。例如,改变,并不会改变主调函数的实参的值。例如,若在执行函数过程中和的值变为和若在执行函数过程中和的值变为和,而和仍为和。,而和仍为和。通常,希
16、望通过函数调用使主调函数能得到一个确通常,希望通过函数调用使主调函数能得到一个确定的值,这就是定的值,这就是函数的返回值函数的返回值。例如,例。例如,例8.8.中,中,(,)的值是,(,)的(,)的值是,(,)的值是值是5 5。赋值语句将这个函数值赋给变量。赋值语句将这个函数值赋给变量。 关于函数返回值的一些说明:关于函数返回值的一些说明: (1)(1)函数的返回值是通过函数中的函数的返回值是通过函数中的returnreturn语句获语句获得的。得的。如果需要从被调用函数带回一个函数值供主调函数使如果需要从被调用函数带回一个函数值供主调函数使用,被调用函数中必须包含用,被调用函数中必须包含re
17、turn语句。如果不需要语句。如果不需要从被调用函数带回函数值可以不要从被调用函数带回函数值可以不要return语句。语句。 一个函数中可以有一个以上的一个函数中可以有一个以上的return语句,执行到哪语句,执行到哪一个一个return语句,哪一个语句起作用。语句,哪一个语句起作用。return语句后面语句后面的括弧也可以不要,的括弧也可以不要,如如: “: “return ;” ;” 等价于等价于 “return ();();” returnreturn语句将被调用函数中的一个确定值带回主调函语句将被调用函数中的一个确定值带回主调函数中去。见图数中去。见图8.28.2中从中从returnr
18、eturn语句返回的箭头。语句返回的箭头。return后面的值可以是一个表达式。后面的值可以是一个表达式。例如,例例如,例8 8中的函数可以改写成:中的函数可以改写成:(int ,int )(? );); (2)(2) 函数的返回值应当属于某一个确定的类型,函数的返回值应当属于某一个确定的类型,在定义函数时指定函数返回值的类型在定义函数时指定函数返回值的类型。 例如例如: :下面是下面是3 3个函数的首行:个函数的首行:int max(float ,float ) /* 函数值为整型函数值为整型 */char letter(char c1,char c2) /* 函数值为字符型函数值为字符型
19、*/ double min(int ,int ) /* 函数值为双精度型函数值为双精度型 */在语言中,凡不加类型说明的函数,自动按整型处在语言中,凡不加类型说明的函数,自动按整型处理。例理。例8.8.中的函数首行的函数类型中的函数首行的函数类型intint可以省可以省写,用写,用turbo c 2.0turbo c 2.0编译程序时能通过,但用编译程序时能通过,但用turbo cturbo c 3.03.0编译程序时不能通过,因为编译程序时不能通过,因为c+c+要求所有函数要求所有函数都必须指定函数类型。因此都必须指定函数类型。因此, ,建议在定义时对所有函数建议在定义时对所有函数都指定函数
20、类型。都指定函数类型。 (3 3)在定义函数时指定的函数类型一般应该和在定义函数时指定的函数类型一般应该和returnreturn语句中的表达式类型一致。语句中的表达式类型一致。如果函数值的类型和如果函数值的类型和return语句中表达式的值不一致,语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。型转换。即函数类型决定返回值的类型。 (4 4)对于不带回值的函数,应当用对于不带回值的函数,应当用“void”void”定定义函数为义函数为“无类型无类型”(或称(或称“空类型空类型”)。这)。这
21、样,系统就保证不使函数带回任何值,即禁止样,系统就保证不使函数带回任何值,即禁止在调用函数中使用被调用函数的返回值。此时在调用函数中使用被调用函数的返回值。此时在函数体中不得出现在函数体中不得出现returnreturn语句。语句。 例例 8.8. 返回值类型与函数类型不同返回值类型与函数类型不同 # include void main()() int (float ,float ); float ,;,; int ; scanf(,);(,); (,);(,); printf( ,);,); int max(float ,float ) float ; /* z为实型变量为实型变量 */ ?
22、 ; return();(); 运行情况如下:, max is 函数调用的一般形式为函数调用的一般形式为: : 函数名函数名(实参表列)(实参表列)如果实参表列包含多个实参,则各参数如果实参表列包含多个实参,则各参数间用逗号隔开。实参与形参的个数应相间用逗号隔开。实参与形参的个数应相等,类型应匹配。实参与形参按顺序对等,类型应匹配。实参与形参按顺序对应,一一传递数据。应,一一传递数据。如果是调用无参函数,则如果是调用无参函数,则“实参表列实参表列”可以没有,但括弧不能省略。可以没有,但括弧不能省略。例例 8 8 实参求值的顺序实参求值的顺序#include void main() int f(
23、int a,int b); /* 函数声明函数声明 */ int i=2,p; p=f(i,+i); /* 函数调用函数调用 */ printf(%dn,p); int f(int a,int b) /* 函数定义函数定义 */ int c; if(ab) c=1; else if(a=b) c=0; else c=-1; return(c); 如果按自左至右顺序求实如果按自左至右顺序求实参的值,则函数调用相当参的值,则函数调用相当于(,)于(,) 如果按自左至右顺序求实如果按自左至右顺序求实参的值,则函数调用相当参的值,则函数调用相当于(于(3,),) 对于函数调用对于函数调用 int i=
24、2,p;p=f(i,+i); 函数语句函数语句把函数调用作为一个语句。如例把函数调用作为一个语句。如例8.1中的中的printstar(),这这时不要求函数带回值,只要求函数完成一定的操作。时不要求函数带回值,只要求函数完成一定的操作。函数表达式函数表达式函数出现在一个表达式中,这种表达式称为函数出现在一个表达式中,这种表达式称为函数表达函数表达式式。这时要求函数带回一个确定的值以参加表达式的。这时要求函数带回一个确定的值以参加表达式的运算。例如运算。例如: :* *(,);(,);函数参数函数参数函数调用作为一个函数的实参。例如函数调用作为一个函数的实参。例如:m = max (a , ma
25、x ( b , c ) ) ;其中其中max ( b , c )是一次函数调用,它的值作为是一次函数调用,它的值作为max另另一次调用的实参。一次调用的实参。m的值是的值是a、b、c三者中的最大者。三者中的最大者。又如又如: printf (%d, max (a,b);也是把也是把max ( a , b )作为作为printf函数的一个参数。函数的一个参数。函数调用作为函数的参数,实质上也是函数表达函数调用作为函数的参数,实质上也是函数表达式形式调用的一种,因为函数的参数本来就要求是表式形式调用的一种,因为函数的参数本来就要求是表达式形式。达式形式。(1) 首先被调用的函数必须是已经存在的首先
26、被调用的函数必须是已经存在的函数(是库函数或用户自己定义的函函数(是库函数或用户自己定义的函数)。但光有这一条件还不够。数)。但光有这一条件还不够。(3) 如果使用用户自己定义的函数,而该如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函函数的位置在调用它的函数(即主调函数)的后面(在同一个文件中),应该数)的后面(在同一个文件中),应该在主调函数中在主调函数中对被调用的函数作声明对被调用的函数作声明。(2) 如果使用库函数,还应该在本文件开如果使用库函数,还应该在本文件开头用命令将调用有关头用命令将调用有关库函数时所需用到的信息库函数时所需用到的信息“包含包含”到本到本文件中
27、来。文件中来。 函数原型的一般形式为函数原型的一般形式为(1)(1) 函数类型函数类型 函数名函数名( (参数类型参数类型1 1,参数,参数类型类型2)2);(2)(2) 函数类型函数类型 函数名函数名( (参数类型参数类型1 1,参数,参数名名1 1,参数类型,参数类型2 2,参数名,参数名2)2); “声明声明”一词的原文是一词的原文是declarationdeclaration,过去在许多书中把它译为过去在许多书中把它译为“说明说明”。声声明的作用明的作用是把函数名、函数参数的个数是把函数名、函数参数的个数和参数类型等信息通知编译系统,以便和参数类型等信息通知编译系统,以便在遇到函数调用
28、时,编译系统能正确识在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。别函数并检查调用是否合法。 (例如(例如函数名是否正确,实参与形参的类型和函数名是否正确,实参与形参的类型和个数是否一致)。个数是否一致)。 注意:注意:函数的函数的“定义定义”和和“声明声明”不是一不是一回事回事。函数的定义函数的定义是指对函数功能的确立,是指对函数功能的确立,包括指定函数名,函数值类型、形参及其包括指定函数名,函数值类型、形参及其类型、函数体等,它是一个完整的、独立类型、函数体等,它是一个完整的、独立的函数单位。而的函数单位。而函数的声明函数的声明的作用则是把的作用则是把函数的名字、函数类型以及
29、形参的类型、函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查。函数时系统按此进行对照检查。 # include void main()() float add(float x, float y);); *对被调用函数对被调用函数add的声明的声明* float a,b,c; scanf(f,f,a,b);); cadd(a,b); printf(sum is f n,c););float add(float ,float ) *函数首部函数首部* float ; /* 函数体函数体 */ z; return(
30、z);); 例例8 对被调用的函数作声明对被调用的函数作声明如果如果 被调用函数的定义出现在主调函数之前,可以不必加以声明。因为编译系统已经先知道了已定义函数的有关情况,会根据函数首部提供的信息对函数的调用作正确性检查。 如果如果 被调用函数的定义出现在主调函数被调用函数的定义出现在主调函数之前,可以不必加以声明。因为编译系之前,可以不必加以声明。因为编译系统已经先知道了已定义函数的有关情况,统已经先知道了已定义函数的有关情况,会根据函数首部提供的信息对函数的调会根据函数首部提供的信息对函数的调用作正确性检查。用作正确性检查。 改写例改写例 8.# include float add(floa
31、t ,float ) *函数首部函数首部* float ; /* 函数体函数体 */ z; return(z);); void main()() float a,b,c; scanf(f,f,a,b);); cadd(a,b); printf(sum is f n,c););函数举例函数举例例例1 计算计算10!+9!+6!例例2 写一个函数使输入的字符串写一个函数使输入的字符串按反次序存放,然后输出。按反次序存放,然后输出。输入输入10个数个数x,计算下列函数值。,计算下列函数值。编写程序计算编写程序计算1+(1+2)+(1+2+3)+(1+n)编写函数计算编写函数计算m!/(m-n)!02
32、sincos02sincosxxxxxxy函数定义的一般格式函数定义的一般格式函数类型函数类型 函数名(形参表)函数名(形参表)/ / 函数首部函数首部 / / 函数体函数体 函数实现过程函数实现过程 return return 表达式;表达式; 形式参数表形式参数表类型类型1 参数参数1 ,类型,类型2 参数参数2 ,类型,类型n 参数参数n 参数之间用逗号分隔,每个参数前面的类型参数之间用逗号分隔,每个参数前面的类型都必须分别写明都必须分别写明 函数定义时的参数被称为形式参数(简称形参)函数定义时的参数被称为形式参数(简称形参)int max(int ,int ) 函数调用时的参数被称为实
33、际参数(简称实参)函数调用时的参数被称为实际参数(简称实参)c= max(a,b) 函数类型函数类型 函数名函数名(参数表参数表);int max(int ,int );函数声明:说明函数的类型和参数的情况,以保函数声明:说明函数的类型和参数的情况,以保证程序编译时能判断对该函数的调用是否正确。证程序编译时能判断对该函数的调用是否正确。函数必须先定义后调用,将主调函数放在被调函函数必须先定义后调用,将主调函数放在被调函数的后面,就像变量先定义后使用一样。数的后面,就像变量先定义后使用一样。如果自定义函数在主调函数的后面,就需要在函如果自定义函数在主调函数的后面,就需要在函数调用前,加上函数原型
34、声明。数调用前,加上函数原型声明。只写函数定义中的第只写函数定义中的第1 1行(函数首部),并以分号结束。行(函数首部),并以分号结束。 实参实参形参形参在参数传递过程中,实参把值复制给形在参数传递过程中,实参把值复制给形参。参。形参和实参一一对应:数量一致,类型形参和实参一一对应:数量一致,类型一致,顺序一致一致,顺序一致形参:变量,用于接受实参传递过来的形参:变量,用于接受实参传递过来的值值实参:常量、变量或表达式实参:常量、变量或表达式#include #include int main(void) int count, m; int prime (int m); count = 0;
35、for(m = 2; m = 100; m+) if ( prime(m) != 0 ) printf(%6d, m ); count+; if (count %10 = 0) printf (n); printf (n);int prime (int m) int i, n; if ( m = 1 ) return 0; n = sqrt (m); for( i = 2; i = n; i+) if (m % i = 0) return 0; return 1; 嵌套定义就在定义一个函数时,其函数体内嵌套定义就在定义一个函数时,其函数体内又包含另一个函数的完整定义又包含另一个函数的完整定义
36、。语言不能嵌套定义函数,但可以嵌套调用语言不能嵌套定义函数,但可以嵌套调用函数,也就是说,在调用一个函数的过程中,函数,也就是说,在调用一个函数的过程中,又调用另一个函数。又调用另一个函数。 例例1 编写一个函数计算编写一个函数计算分析分析 编写一个函数计算编写一个函数计算i!,然后编写!,然后编写函数函数c(n,m)计算计算 mnc)!( !mnmncmnmnc计算阶乘的函数计算阶乘的函数 int fac(int i) int k,f=1; for(k=1;k=i;k+) f*=k; return (f);计算计算c(n,m)的函数的函数 int cnm(int n,int m) int c
37、; c=fac(n)/(fac(m)*fac(n-m); return (c);调用函数调用函数c(n,m)计算计算 void main() int c,n,m; n=9;m=5; (或或 scanf(“%d%d”,&n,&m);) c=cnm(n,m); printf(“%d”,c);59c 在调用一个函数的过程中又出现直接或间接地在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。语调用该函数本身,称为函数的递归调用。语言的特点之一就在于允许函数的递归调用。言的特点之一就在于允许函数的递归调用。例例 8 有个人坐在一起,问第个人多少岁?有个人坐在一起,问第个人多少岁
38、?他说比第个人大岁。问第个人岁数,他说比第他说比第个人大岁。问第个人岁数,他说比第个人大岁。问第个人,又说比第个人大岁。个人大岁。问第个人,又说比第个人大岁。问第个人,说比第个人大岁。最后问第个人,问第个人,说比第个人大岁。最后问第个人,他说是岁。请问第个人多大。他说是岁。请问第个人多大。 ()()()()()()()()()()()()()()()()()()可以用数学公式表述如下:可以用数学公式表述如下: age(n) ()() age(n)=age(n-1) ()()可以用一个函数来描述上述递归过程:可以用一个函数来描述上述递归过程:int age(int ) *求年龄的递归函数求年龄的
39、递归函数* int ; * 用作存放函数的返回值的变量用作存放函数的返回值的变量 * if()() ; else ();(); return();();用一个主函数调用用一个主函数调用age函数,求得第函数,求得第5人的年龄。人的年龄。#include void main()() printf(%d,age(5); 运行结果如下:运行结果如下: 例例8.8.用递归方法求!用递归方法求! 求!也可以用递归方法,即!等于求!也可以用递归方法,即!等于!,而,而!,!。!。可用下面的递归公式表示:可用下面的递归公式表示: ! (,)(,) ()!()! ()() long fac (int n) l
40、ong f;if (n=0) f=1; else f=n*fac(n-1); return f; 例例8.8 8.8 用递归函数计算用递归函数计算n!n!例例8.98.9用递归法计算用递归法计算n n阶勒让德多项式的值阶勒让德多项式的值float p(int n, float x) float q; if (n=0)q=1.0; else if(n=1) q=x; else q=(2*n-1)*x*p(n-1,x)-(n-1)*p(n-2,x)/n; return(q); 1 /)() 1()() 12(1 0 1)(21nnxpnxxpnnxnxpnnn采用采用“值传送值传送”方式。方式。
41、可以用数组名作函数参数,此时形参应当用数可以用数组名作函数参数,此时形参应当用数组名或用指针变量组名或用指针变量 。形参数组可不指定大小。形参数组可不指定大小。例例 8.13 用选择法对数组中用选择法对数组中10个整数按由个整数按由小到大排序。小到大排序。程序实例程序实例#include void main()() void sort(int array,int ); int a10,i; printf(enter the arrayn);); for(i=0;i10;i+) scanf(”%d”,&ai);); sort(a,10);); printf(the sorted array:n)
42、;); for(i=0;i10;i+) printf(”%d”,ai);); printf(n);); void sort(int array,int n) int i,j,k,t; for(i=0;in-1;i+) ki; for(j=i+1;jn;j+) if(arrayj arrayk)k=j; t=arrayk; arrayk=arrayi; arrayi=t; 程序如下:程序如下:#include void main()() int max_value ( int array4); int a34=1,3,5,7,2,4,6,8,15,17,34,12; printf(max val
43、ue is , max_value(a) );); int max_value ( int array 4) int i,j,k,max; max=array00; for(i=0;i3;i+) for(j=0;jmax) max= array ij; return(max);); 运行结果如下:运行结果如下:max value is 34l 局部变量局部变量p在函数内定义的变量(包括形参)在函数内定义的变量(包括形参) 作用范围:本函数内部作用范围:本函数内部 定义在复合语句内的变量定义在复合语句内的变量 作用范围:复合语句内部作用范围:复合语句内部l 全局变量全局变量p在函数以外定义的变量
44、,不从属于任一函数。在函数以外定义的变量,不从属于任一函数。 作用范围:从定义处到源文件结束作用范围:从定义处到源文件结束(包括各函(包括各函数)数)#include int main (void) int a; a = 1; /* 复合语句开始复合语句开始 */ int b = 2; b = a + b; a = a + b; /* 复合语句结束复合语句结束 */ printf (%d , a ); return 0;b:b:小范围内的临时变量小范围内的临时变量 4在函数内定义的变量是局部变量在函数内定义的变量是局部变量,而在函数之而在函数之外定义的变量称为外部变量外定义的变量称为外部变量,
45、外部变量是全局外部变量是全局变量变量(也称全程变量也称全程变量)。全局变量可以为本文件。全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。量的位置开始到本源文件结束。 例例 8.15 有一个一维数组,内放个学生成绩,写有一个一维数组,内放个学生成绩,写一个函数,求出平均分、最高分和最低分。一个函数,求出平均分、最高分和最低分。 #include float max,min; *全局变量全局变量*void main() float average(float array,int n); float ave,score1
46、0; int ; for(i=0;i10;i+) scanf(%f,&scorei);); ave= average(score,10);); printf(“max=%6.2fnmin=%6.2fn average=%6.2fn“,max,min,ave); float average(float array,int n) * 定义函数,形参为数组定义函数,形参为数组 */ int ; float aver,sum=array0; max=min=array0; for(i=1;in;i+) if(arrayimax)maxarrayi; else if(arrayimin)min arra
47、yi; sum=sum+arrayi; aversum/n; return aver ; 建议不在必要时不要使用全局变量,原因如下:建议不在必要时不要使用全局变量,原因如下: 全局变量在程序的全部执行过程中都占用存储单全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。元,而不是仅在需要时才开辟单元。 使用全局变量过多,会降低程序的清晰性,人们使用全局变量过多,会降低程序的清晰性,人们往往难以清楚地判断出每个瞬时各个外部变量的值。往往难以清楚地判断出每个瞬时各个外部变量的值。在各个函数执行时都可能改变外部变量的值,程序在各个函数执行时都可能改变外部变量的值,程序容易出错。
48、因此,要限制使用全局变量。容易出错。因此,要限制使用全局变量。它使函数的通用性降低了,因为函数在执行时要它使函数的通用性降低了,因为函数在执行时要依赖于其所在的外部变量。依赖于其所在的外部变量。 前面已介绍了从变量的作用域(即从空间)角度来前面已介绍了从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量。那么从变量值分,可以分为全局变量和局部变量。那么从变量值存在的时间(即生存期)角度来分,又可以分为静存在的时间(即生存期)角度来分,又可以分为静态存储方式和动态存储方式。态存储方式和动态存储方式。 所谓静态存储方式是指在程序运行期间由系统分所谓静态存储方式是指在程序运行期间由系统分配
49、固定的存储空间的方式。而动态存储方式则是在配固定的存储空间的方式。而动态存储方式则是在程序运行期间根据需要进行动态的分配存储空间的程序运行期间根据需要进行动态的分配存储空间的方式。这个存储空间可以分为三部分:方式。这个存储空间可以分为三部分: 程序区程序区静态存储区静态存储区动态存储区动态存储区存储类别指的是数据在内存中存储的方式。存存储类别指的是数据在内存中存储的方式。存储方式分为两大类:储方式分为两大类: 静态存储类和动态存储类。静态存储类和动态存储类。具体包含四种:具体包含四种: 自动的自动的()() 静态的静态的()() 寄存器的寄存器的()() 外部的外部的()()根据变量的存储类别
50、,可以知道变量的作用域根据变量的存储类别,可以知道变量的作用域和生存期。和生存期。 l 函数中的局部变量,数据存储在动态存储区中函数中的局部变量,数据存储在动态存储区中l 函数中的形参、在函数中定义的变量和复合语句中定函数中的形参、在函数中定义的变量和复合语句中定 义的变量,都属义的变量,都属auto类。类。l 在调用该函数时系统会给它们分配存储空间,在函数调在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。自动变量用关键字作存储类别的声为自动变量。自动变量用关键字作存储类别的声明。例
51、如:明。例如: int (int ) *定义定义f函数,为形参函数,为形参 *auto int ,;,; *定义、为自动变量定义、为自动变量 * int (int ) int ,;,; 有时希望函数中的局部变量的值在函数调用结有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,即其占用的存储单元不释束后不消失而保留原值,即其占用的存储单元不释放,在下一次该函数调用时,该变量已有值,就是放,在下一次该函数调用时,该变量已有值,就是上一次函数调用结束时的值。这时就应该指定该局上一次函数调用结束时的值。这时就应该指定该局部变量为部变量为“静态局部变量静态局部变量”,用关键字,用关键字进行声
52、明。通过下面简单的例子可以了解它的特进行声明。通过下面简单的例子可以了解它的特点。点。#include void fun (int k);int main (void) int k; for (k = 1; k = 3; k+) fun (k); return 0; void fun(int k) static int a; printf (%d, , a); a += k ; 0,1,3,静态变量会记住前一次调用时留下来的值静态变量会记住前一次调用时留下来的值静态变量的初值为静态变量的初值为0对静态局部变量的说明:对静态局部变量的说明:(1) 静态局部变量属于静态存储类别,在静态存储区内静态
53、局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动动变量(即动态局部变量)属于动态存储类别,占动态存储区空间而不占静态存储区空间,函数调用结束态存储区空间而不占静态存储区空间,函数调用结束后即释放。后即释放。(2) 对静态局部变量是在编译时赋初值的,即只赋初值对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值。一次,在程序运行时它已有初值。以后每次调用函数以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的时不再重新赋初值而只是保留上次
54、函数调用结束时的值。值。而对自动变量赋初值,不是在编译时进行的,而而对自动变量赋初值,不是在编译时进行的,而是在函数调用时进行,每调用一次函数重新给一次初是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。值,相当于执行一次赋值语句。(3)如在定义局部变量时不赋初值的话,则对静态局如在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值(对数值型变量)部变量来说,编译时自动赋初值(对数值型变量)或空字符(对字符变量)。或空字符(对字符变量)。而对自动变量来说,如而对自动变量来说,如果不赋初值则它的值是一个不确定的值。这是由于果不赋初值则它的值是一个不确定的值
55、。这是由于每次函数调用结束后存储单元已释放,下次调用时每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是又重新另分配存储单元,而所分配的单元中的值是不确定的。不确定的。(4) 虽然静态局部变量在函数调用结束后仍然存在,虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的。但其他函数是不能引用它的。8.9.4 register变量变量 寄存器变量寄存器变量,用关键字,用关键字register作声明。例如,例作声明。例如,例819中的程序是输出到中的程序是输出到n的阶乘的值。的阶乘的值。例例819 使用寄存器变量使用寄存器变量#include v
56、oid main ( )long fac(long); long i,n; scanf(%ld,&n); for(i=1;i=n;i+) printf(%ld!=%ldn,i,fac(i);long fac(long n)register long i,f=1; /*定义寄存器变量定义寄存器变量*/ for (i=1;i=n;i+) f=f*i; return (f);8.5 用用extern声明外部变量声明外部变量外部变量是在函数的外部定义的全局变量,它的外部变量是在函数的外部定义的全局变量,它的作用域是从变量的定义处开始,到本程序文件的末作用域是从变量的定义处开始,到本程序文件的末尾。在此
57、作用域内,全局变量可以为程序中各个函尾。在此作用域内,全局变量可以为程序中各个函数所引用。编译时将外部变量分配在静态存储区。数所引用。编译时将外部变量分配在静态存储区。有时需要用有时需要用extern来声明外部变量,以扩展外部变来声明外部变量,以扩展外部变量的作用域。量的作用域。1. 在一个文件内声明外部变量在一个文件内声明外部变量例例820 用用extern声明外部变量,扩展它在程序文声明外部变量,扩展它在程序文件中的作用域。件中的作用域。#include void main() int max(int,int); *外部变量声明外部变量声明* extern a,b; printf(%dn,
58、max(a,b);int a=13,b=-8; *定义外部变量定义外部变量*int max(int x,int y) *定义函数定义函数 * int z; z=xy?x:y; return(z); 2. 在多文件的程序中声明外部变量在多文件的程序中声明外部变量例例8 用用extern将外部变量的作用域扩展到其他将外部变量的作用域扩展到其他文件。文件。 本程序的作用是给定的值,输入和,求本程序的作用是给定的值,输入和,求和和am的值。文件的值。文件file中的内容为:中的内容为:# include int a; /*定义外部变量定义外部变量*/void main() int (int);); /
59、*函数声明函数声明*/ int ,;,; printf(enter the number a and its power m:n);); scanf(,a,);,); a*; printf(*,a,);,); ();(); printf(*n,a,);,); 文件文件file中的内容为:中的内容为:extern a; /*声明声明a为一个已定义的外部变量为一个已定义的外部变量*/ int (int );int ,;,; for(;)(;) *a; ();(); 8.9.6用用static声明外部变量声明外部变量有时在程序设计中希望某些外部变量只限于被本文件有时在程序设计中希望某些外部变量只限于
60、被本文件引用,而不能被其他文件引用。这时可以在定义外部引用,而不能被其他文件引用。这时可以在定义外部变量时加一个声明。变量时加一个声明。例如:例如:file1.c file2.cstatic int a; extern int a;/*cant use a in file1.cvoid main ( ) void fun (int n) a=a*n; 例例1 main() int i; for(i=0;i3;i+) add(); add() static int x=0; x+; printf(“%dn”,x); 例例2 main() int x=10; func(x); printf(“%d
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 妇科护理中的患者教育与管理
- 心肌病患者的护理质量改进
- 插花与花艺设计(第4版)课件 项目1 插花花艺基本知识
- 冬季XX县XX农村自建房消防安全隐患排查
- 2024-2025学年度计算机四级试题预测试卷带答案详解(典型题)
- 2024-2025学年度电梯考试模考模拟试题含答案详解【突破训练】
- 2024-2025学年度医院三基考试考前冲刺试卷含完整答案详解(各地真题)
- 2024-2025学年度公务员考试《常识》测试卷及参考答案详解【模拟题】
- 2024-2025学年度医院三基考试模拟试题含答案详解(培优)
- 2026年医保报销政策试题及答案
- 体外受精-胚胎移植(IVF-ET)全流程管理与质量控制实践指南
- 玻璃外墙清洗合同范本
- 2025年浙江二级造价师建设工程计量与计价土建真题及答案
- 缩宫素点滴引产术课件
- 雨课堂在线学堂《中国传统文化》课后单元测试答案
- 三层办公楼结构设计计算书
- 2026年洛阳文化旅游职业学院单招综合素质考试题库新版
- 高中历史名词解释+知识清单+2025-2026学年高考二轮精准复习
- 机场搬运工考试题及答案
- GB/T 3286.2-2025石灰石及白云石化学分析方法第2部分:硅、铝含量的测定
- 2025年贵州分类考试试题及答案
评论
0/150
提交评论