版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、14.1 4.1 概述概述4.2 4.2 函数的定义与声明函数的定义与声明4.3 4.3 函数调用函数调用4.4 4.4 函数返回类型与返回值函数返回类型与返回值4.5 4.5 函数的参数函数的参数4.6 4.6 递归递归4.7 4.7 变量作用域变量作用域4.8 4.8 变量存储类别变量存储类别4.9 4.9 内部函数和外部函数内部函数和外部函数4.10 4.10 预处理预处理4.11 4.11 案例应用案例应用21. 函数的概念函数的概念u在C语言程序设计中,具有特定功能的子模块对应为“函数”。函数是一个命名的程序段,负责完成特定的、相对独立的动作或计算。u可以把函数看成是一个“黑盒子”,
2、只要输入数据就能得到结果,函数内部究竟是如何工作,外部程序不得而知,外部程序所知道的仅限于输入给函数什么以及函数输出什么。3#include #include / / 数学函数库对应头文件数学函数库对应头文件math.hmath.h void main() double x, y; scanf(x=%lf, &x); y=sin(x); / /调用正弦函数调用正弦函数sin()sin() printf(sin(%6.2lf)=%6.2lfn, x, y);当输入当输入x=1.57x=1.57,程序运行结果,程序运行结果:sin( 1.57)= 1.004#include void ma
3、in()void print_star(); void print_message(); print_star(); print_message(); print_star(); void print_star () printf(*n);void print_message() printf( How do you do!n);输出输出18个个*输出一行文字输出一行文字声明函数声明函数定义函数定义函数 * How do you do! *5说明:说明:(1) 一个程序由一个或多个程序模块组成一个程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。 对于较大的程序,一般不把所有内容
4、全放在一个源程序文件中,而是将它们分别放在若干个源文件中,由若干个源程序文件组成一个C程序。 便于分别编写、分别编译,提高调试效率。一个源程序文件可以为多个C程序所调用。6(2) 一个源程序文件由一个或多个函数组成一个源程序文件由一个或多个函数组成。一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位进行编译的,而不是以函数为单位进行编译的。(3) C语言程序中必须包含一个并且仅包含一个以main()为名的函数, 这个函数称为主函数为主函数。不论main函数出现在什么位置,总是从总是从main函数开始函数开始执行执行。如果在main函数中调用其他函数,在调用后流程返回到main函数,
5、在main函数中结束整个程序的运行。7(4) 所有函数都是平行的,即在定义函数时是分别进行的,是互相独立的互相独立的。一个函数并不从属于另一个函数,即函数不能嵌套定义不能嵌套定义。函数间可以互相调用,但不能调用main函数。main函数是由系统调用的。82. 函数的分类函数的分类从用户使用的角度看,函数有两种。u库函数库函数,它是由系统提供的,用户不必自己定义而直接使用它们。应该说明,不同的C语言编译系统提供的库函数的数量和功能会有一些不同,当然许多基本的函数是共同的。u用户自定义的函数用户自定义的函数。它是用以解决用户专门需要的函数。92. 函数的分类函数的分类从函数的形式看,函数分两类。
6、无参函数无参函数。函数没有参数,一般用来执行固定的一组操作。无参函数可以带回或不带回函数值,但一般以不带回函数值的居多。 有参函数有参函数。在调用函数时,要给出实参。主调函数在调用被调用函数时,通过参数向被调用函数传递数据,一般情况下,执行被调用函数时会得到一个函数值,供主调函数使用。10使用库函数,应注意以下几点:使用库函数,应注意以下几点:u类别不同的库函数被包含在不同的头文件中。 u当需要使用某个库函数时,应在程序开头用#include预处理命令将对应的头文件包含进来。u调用库函数时,应遵循下面的格式: 函数名(函数参数)函数名(函数参数) 函数参数可以是常量、变量或者表达式。在调用函数
7、时,函数名、函数参数以及参数的类型必须与函数原型一致。11u函数的定义和声明是两件不同的事情。函数的定义和声明是两件不同的事情。u函数的定义函数的定义是指依照函数定义的格式,编写若是指依照函数定义的格式,编写若干程序语句以实现函数的功能。干程序语句以实现函数的功能。u函数的声明函数的声明是指在函数定义好之后,在调用之是指在函数定义好之后,在调用之前对函数的类型和参数的类型进行说明。前对函数的类型和参数的类型进行说明。 12uC语言要求,在程序中用到的所有函数,必须“先先定义,后使用定义,后使用”。131.怎样定义无参函数怎样定义无参函数u函数名后面圆括号中空的,没有参数u定义无参函数的一般形式
8、为: 类型名类型名 函数名函数名() 函数体函数体 包括声明部分包括声明部分和语句部分和语句部分指定函数指定函数值的类型值的类型圆括号不能省略圆括号不能省略 141.怎样定义无参函数怎样定义无参函数u函数名后面圆括号中空的,没有参数u定义无参函数的一般形式为: void 函数名函数名() 函数体函数体 包括声明部分包括声明部分和语句部分和语句部分表示不需要表示不需要带回函数值带回函数值152. 有参函数的一般形式为有参函数的一般形式为: : 类型标识符类型标识符 函数名(形式参数表列)函数名(形式参数表列) 声明部分声明部分 语句部分语句部分 16float max1 (float x,flo
9、at y) float m; m=(xy)?x:y; return(m); 函数的功能函数的功能是什么是什么?求求x和和y二者二者中大者中大者void max2 () float x,y,m; scanf(%f%f,&a,&b); m=(xy)?x:y; printf(max is %6.2fn,m); 17说明:说明:u函数定义包括两部分:函数首部和函数体。函数定义包括两部分:函数首部和函数体。u函数首部函数首部由函数名、形式参数列表和返回数由函数名、形式参数列表和返回数据类型组成。据类型组成。u函数体函数体包括声明部分和语句部分,由一对花包括声明部分和语句部分,由一对花括号
10、括号以及其中的语句序列组成。以及其中的语句序列组成。 u函数名必须是一个合法的标识符,用来唯一函数名必须是一个合法的标识符,用来唯一标识该函数。标识该函数。 18说明:说明:u不论函数的形式参数类型是否相同,必须分别不论函数的形式参数类型是否相同,必须分别说明参数类型。说明参数类型。 如:如: (float a, float bfloat a, float b) 不能写成不能写成(float a, bfloat a, b)。)。u在函数体中也应将变量的声明放在使用该变量在函数体中也应将变量的声明放在使用该变量之前,否则会出现编译错误。之前,否则会出现编译错误。19在一个函数中调用另一个函数需要
11、具备如下条件:在一个函数中调用另一个函数需要具备如下条件:(1) 被调用函数必须是已经定义的函数(是库函被调用函数必须是已经定义的函数(是库函数或用户自己定义的函数)数或用户自己定义的函数)。(2) 如果使用库函数,应该在本文件开头如果使用库函数,应该在本文件开头加相应加相应的的#include指令指令。(3) 如果使用自己定义的函数,而该函数的位置如果使用自己定义的函数,而该函数的位置在调用它的函数后面在调用它的函数后面,应该应该进行函数进行函数声明声明。20函数声明的形式函数声明的形式: :函数类型函数类型 函数名函数名( (形式参数类型,形式参数名形式参数类型,形式参数名) );u函数声
12、明的形式与函数定义时的首部是相同的,只要加一个分号就成为函数声明。由于函数声明与函数首部的一致,故把函数声明称为函数原型函数原型。u声明的作用声明的作用是把函数名、函数值类型、参数个数、参数类型和参数顺序等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。21例:例:float max1(float a, float b);函数声明中参数名可以省写,可写成:float max1(float, float);float max1(float x, float y); 函数原型的一般形式为函数原型的一般形式为: : 1. 1.函数类型函数类型 函数名函数名( (参数
13、类型参数类型1 1,参数类型,参数类型2)2); 2.2.函数类型函数类型 函数名函数名( (参数类型参数类型1 1,参数名,参数名1 1, 参数类型参数类型2 2,参数名,参数名2)2); 22函数的函数的“定义定义”和和“声明声明”不是一回事。不是一回事。u函数的定义函数的定义是指对函数功能的确立函数功能的确立,包括指定函数名,函数值类型、形参及其类型、函数体函数体等,它是一个完整的、独立的函数单位。u函数的声明函数的声明的作用则是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查。它不包含函数体函数体。 23说明:说明: (1)如果被调用
14、函数的定义出现在主调函数之前,可以不必加以声明。 (2) 如果已在文件的开头(在所有函数之前),已对本文件中所调用的函数进行了声明,则在各函数中不必对其所调用的函数再作声明 。 241 1、函数调用的一般形式为、函数调用的一般形式为: : 函数名函数名(实参表列)(实参表列)(1)调用无参函数的形式: 函数名函数名( )( ) 如:print_star()(2)调用有参函数的形式: 函数名(函数名(实参表列实参表列) 如:max1(x,y)如果有多个参数,如果有多个参数,用逗号隔开用逗号隔开圆括号不能省略圆括号不能省略 25调用有参函数的形式: 函数名(函数名(实参表列实参表列)常量、变量或表
15、达式常量、变量或表达式如果实参表列包括多个实参,对实参求值的顺序并不是确定的,有的系统按自左至右顺序求实参的值,有的系统则按自右至左顺序。例例如如: (,+);); 若的原值为,在 VC+ 6.0环境下运行的结果不是“3,4”,而为“4,4”。262 2、调用函数的方式:调用函数的方式:按函数在程序中出现的位置分,有按函数在程序中出现的位置分,有3种函数调用方式种函数调用方式() 函数语句函数语句 调用调用无无返回值的函数,函数调用单独作为一个语句返回值的函数,函数调用单独作为一个语句 例例如:如:printf(“Hello,C!”);27() 函数表达式函数表达式 函数出现在一个表达式中,这
16、种表达式称为函数表函数出现在一个表达式中,这种表达式称为函数表达式达式,要求函数返回一个确定的值以参加表达式的运算。,要求函数返回一个确定的值以参加表达式的运算。 例如:例如:double z,a; z=a+sqrt(100);28() 函数参数函数参数 函数调用作为一个函数的实参函数调用作为一个函数的实参。 例例如如:float m,a,b,c; m=max1(a,max1(b,c); 其中max1(b,c)是一次函数调用,它的值作为max1另一次调用的实参。m的值是a、b、c三者中的最大者。293 3、函数函数调用过程调用过程:u一个一个C程序可以包含多个函数,但必须包含且只能程序可以包含
17、多个函数,但必须包含且只能包含一个包含一个main()函数。函数。u程序的执行从程序的执行从main()函数开始,到函数开始,到main()函数结函数结束。程序中的其它函数必须通过束。程序中的其它函数必须通过main()函数直接或函数直接或者间接地调用才能执行。者间接地调用才能执行。u注意:注意:main()函数可以调用其它函数,但不允许被函数可以调用其它函数,但不允许被其它函数调用。其它函数调用。main()函数是由系统自动调用的。函数是由系统自动调用的。30#includefloat max1(float a, float b);void main() float x,y,z; print
18、f(input two numbers: ); scanf(%f%f,&x,&y); z=max1(x,y); printf(max is %6.2fn,z);【例4.3】比较两个数的大小,输出较大值。 /调用函数调用函数31float max1(float a, float b) float m; m=ab?a:b; return (m);参数类型参数类型函数类型函数类型定义函数定义函数定义函数内定义函数内使用的变量使用的变量32 z=max1(x,y); /main函数函数float max1(float a, float b) /max1函数函数 float m; m=a
19、b?a:b; return(m); 33#includefloat max1(float a, float b);void main() float x,y,z; printf(input two numbers: ); scanf(%f%f,&x,&y); z=max1(x,y); printf(max is %6.2fn,z);float max1(float a, float b) float m; m=ab?a:b; return (m);if (ab) return(a);else return(b);形式参数形式参数实际参数实际参数return(ab?a:b);34
20、4 4、函数函数的嵌套的嵌套调用:调用:函数之间都是平行的,可以在一个函数中调用另一函数之间都是平行的,可以在一个函数中调用另一个函数。当被调函数的定义中又包含了对第三个函数个函数。当被调函数的定义中又包含了对第三个函数的调用,这就构成了函数的的调用,这就构成了函数的嵌套调用嵌套调用。 mainmain函数函数调用调用a a函数函数结束结束a a函数函数调用调用b b函数函数b b函数函数35#includeint gcd(int a, int b);int lcm(int a, int b);void main() int a,b,m,n; printf(please input a,b:
21、); scanf(%d,%d,&a,&b); m=gcd(a,b); n=lcm(a,b); printf(gcd(%d,%d)=%dn,a,b,m); printf(lcm(%d,%d)=%dn,a,b,n);【例4.4】编写函数求两个正整数的最大公约数和最小公倍数。 主函数主函数函数声明函数声明函数调用函数调用输入输入2个整数个整数36int gcd(int a, int b) int t; do t=a%b; a=b; b=t; while(b!=0); return (a); gcd函数函数最大公约数最大公约数辗转相除法辗转相除法该算法在例该算法在例3.14讲解讲解过过
22、如:如: 当当a=36,b=24时时 返回值为:返回值为:1237int lcm(int a, int b) int t; t=a*b/gcd(a,b); return (t);lcm函数函数最小公倍数最小公倍数最小公倍数最小公倍数=数数1*数数2/最大公约数最大公约数如:如: 当当a=36,b=24时时 gcd函数的返回值:函数的返回值:12 t=36*24/12 返回值为:返回值为:7238int lcm(int a, int b) int t; t=a*b/gcd(a,b); return (t);#includevoid main() m=gcd(a,b); n=lcm(a,b); i
23、nt gcd(int a, int b) int t; do t=a%b; a=b; b=t; while(b!=0); return (a); 39u函数的返回类型函数的返回类型是在函数定义时函数首部指定的类型。u函数的返回值函数的返回值是指函数被调用时,执行函数体中的程序段后所取得的并返回给主调函数的值。u函数的返回值可以有,也可以没有。u根据返回值的有无,可以将函数分为有返回值函有返回值函数数和无返回值函数无返回值函数两类。401 1、有返回值函数、有返回值函数通过通过returnreturn语句将值返回给主调函数。语句将值返回给主调函数。returnreturn语句的一般形式:语句的一
24、般形式: return 表达式表达式; 或或 return(表达式表达式);功能:功能:计算表达式的值,并返回给主调函数。计算表达式的值,并返回给主调函数。 例:例:return(a); return(ab?a:b);此处应有一个空格此处应有一个空格 特殊形式:特殊形式: return; /表示返回主调函数,但不带回值。表示返回主调函数,但不带回值。41说明:说明: u一个函数可以有一个或者多个return语句,但每次调用只能有一个return语句被执行,因此只能返回一个函数值。u当一个函数有返回值时,必须在函数定义时指定函数的返回类型。如果省略函数的返回类型,则系统默认函数返回类型为int型
25、。u函数返回类型应该和return语句中表达式值的类型一致。以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。函数类型决定返回值的类型。42#includemax1(float a, float b); void main() float x,y,z; printf(input two numbers: ); scanf(%f%f,&x,&y); z=max1(x,y); printf(max is %6.2fn,z);【例4.5】函数返回类型与return表达式值类型不一致。 max1(float a, float b) float m; m=a
26、b?a:b; return (m);max1()函数的返回函数的返回类型默认为类型默认为int 表达式类型为表达式类型为float尽量保证函数返回类型与尽量保证函数返回类型与returnreturn表达式值的类型相同表达式值的类型相同 432 2、无返回值函数、无返回值函数可以明确定义为可以明确定义为“空空”类型,类型说明符为类型,类型说明符为“void”。 此时在函数体中不应出现此时在函数体中不应出现return语句或语句或return语句语句后面不带任何表达式。后面不带任何表达式。 void printstar() printf(*);该函数不能参与表达式运算。该函数不能参与表达式运算。如
27、下面的用法就是错误的:如下面的用法就是错误的: a=b+printstara=b+printstar();(); m=printstar m=printstar();();编译时会给出出错信息。编译时会给出出错信息。44u形式参数形式参数:函数名后面圆括号“()”中的参数,简称形参形参。形参在定义时必须指明它的个数,类型和名字。当有多个形参时,参数之间用逗号间隔。u实际参数实际参数是指在调用一个有参函数时,函数名后面圆括号“()”中的参数,简称实参实参。实参可以是常量、变量、表达式、函数等。u在进行函数调用时,实参必须具有确定的值,以便将这些值传送给形参。45参数传递方式有两种:参数传递方式有
28、两种:值传递值传递和和地址传递地址传递。 1 1、值传递、值传递 根据实参和形参的对应关系,将实参的值根据实参和形参的对应关系,将实参的值单向单向地地传递给形参,供被调函数在执行时使用。在函数执传递给形参,供被调函数在执行时使用。在函数执行过程中,对形参做任何修改都不影响实参的值。行过程中,对形参做任何修改都不影响实参的值。int func(int x, int y) y=x+y; return (y);假设假设a=3,b=4,执行执行 m=func(a,b);46u在定义函数中指定的形参,在未出现函数调用时,在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调
29、用时,它们并不占内存中的存储单元。在发生函数调用时,函数函数func的形参被临时分配内存单元。的形参被临时分配内存单元。u在函数调用时,实参的值应一一对应地传递给形参,在函数调用时,实参的值应一一对应地传递给形参,实参与形参的个数应相同,类型应一致。实参与形参的个数应相同,类型应一致。3a4bxy34实参实参形参形参调用函数时调用函数时473a4bxy37实参实参形参形参调用结束,调用结束,形参单元被释放形参单元被释放实参单元仍保留并维持原值,没有改变实参单元仍保留并维持原值,没有改变如果在执行一个被调用函数时,形参的值发生如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数的实参的
30、值改变,不会改变主调函数的实参的值调用结束调用结束48【例4.6】从m个不同元素中取出n(nm)个元素的所有组合的个数,叫做从m个不同元素中取出n个元素的组合数。求组合数:C(m,n)= , 如 。分析:分析: 定义一个求n!的函数fac,主函数中三次调用fac函数实现求组合数。 n)!-m(*m!m!154*26C26!49#includeint fac (int n);void main() int m, n, c; printf(please input m,n(m=n): ); scanf(%d%d, &m,&n); c=fac(m)/fac(n)/fac(m-n);
31、printf(C(%d,%d)=%dn,m,n,c);int fac (int n) int i, t=1; for(i=1;i=n;i+) t=t*i; return (t);定义定义fac()函数求函数求n的阶乘。的阶乘。用于存放累积用于存放累积C(m,n)=n)!-m(*m!m!c=fac(m)/(fac(n)*fac(m-n);50void swap(int x, int y) int t; t=x;x=y;y=t;#includevoid swap(int x, int y);void main() int a=2, b=4; printf(before swap:n); print
32、f(a=%d, b=%dn, a, b); swap(a,b); printf(after swap:n); printf(a=%d, b=%dn, a, b);【例4.7】交换变量a、b的值 。before swap:a=2,b=4after swap:a=2,b=4 ?51【例4.7】交换变量a、b的值 。2a4bxy24实参实参形参形参调用函数时调用函数时2a4bxy24实参实参形参形参执行函数执行函数t2422a4bxy42实参实参形参形参调用结束调用结束函数的参数传递方函数的参数传递方式是单向值传递。式是单向值传递。52参数传递方式有两种:参数传递方式有两种:值传递值传递和和地址传递
33、地址传递。 2 2、地址传递、地址传递 函数参数传递的另一种方式为地址传递。这时函数参数传递的另一种方式为地址传递。这时作为参数传递的不再是变量的值,而是变量的作为参数传递的不再是变量的值,而是变量的存储地址。有关地址传递的内容,将在第存储地址。有关地址传递的内容,将在第6 6章中章中详细介绍。详细介绍。53【例【例6.166.16】用指针进行两个变量值的交换用指针进行两个变量值的交换。#includevoid main() void swap(int *x,int *y); /函数声明函数声明 int a=15, b=8; printf(before swap: a=%d,b=%dn,a,b
34、); swap(&a, &b); printf(after swap: a=%d,b=%dn,a,b);54void swap(int *x,int *y) int temp;temp = *x;*x = *y;*y = temp;ab158x&ay &b815 指针作函数的参数,不仅能保留函数中对实参的修指针作函数的参数,不仅能保留函数中对实参的修改,而且由于传递的是地址,不需要生成实参的副改,而且由于传递的是地址,不需要生成实参的副本,因此参数传递的效率较高,特别是传递本,因此参数传递的效率较高,特别是传递“体积体积” ” 较大的数据,如数组、结构体等。较大
35、的数据,如数组、结构体等。55递归的概念递归的概念在调用一个函数的过程中又出现直接或间接在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的地调用该函数本身,称为函数的递归调用递归调用。语言的特点之一就在于允许函数的递归调语言的特点之一就在于允许函数的递归调用。用。56 f2函数函数调用调用f1函数函数 int fn(int a) int x,y; y=fn(x); return (3*y); fn函数函数调用调用fn函数函数 f1函数函数调用调用f2函数函数应使用应使用if语句控制结束调用语句控制结束调用直接调用本函数直接调用本函数间接调用本函数间接调用本函数57【问题】求解自
36、然数【问题】求解自然数n的阶乘。的阶乘。1.用递推方法求用递推方法求!解题思路: 从1开始,乘2,再乘3一直乘到n。这种方法容易理解,也容易实现。递推法的特点是从一个已知的事实出发,按一定规律推下一个事实,再从这个新的已知的事实出发,再向下推出一个新的事实这是和递归不同的。58#include void main() int n; long fact=1; printf(“input an integer number:”); scanf(“%d”,&n); for(i=1;i=n;i+) fact=fact*i; printf(“%d!=%ldn”,n,fact); 如何用函数来实现
37、?如何用函数来实现?59#include long fac(int n); void main() int n; long fact=1; printf(“input an integer number:”); scanf(“%d”,&n); fact=fac(n); printf(“%d!=%ldn”,n,fact); long fac(int n) int i; long fact=1; for(i=1;i=n;i+) fact=fact*i; return(fact);60【问题】求解自然数【问题】求解自然数n的阶乘。的阶乘。2.用递归方法求用递归方法求!解题思路: 直接从目标出
38、发提出问题: !等于!,而!,而1!是已知的,不必再回溯了。) 1()!1() 1 , 0(1!nnnnnn615!=4!*5 4! =3!*4 3! =2!*3 2! =1!*2 1! =1 2! =1*2=2 3! =2*3=6 4! =6*4=24 5! =24*5=120 递推阶段递推阶段 回归阶段回归阶段结束递归的条件结束递归的条件62#includeint fac(int n);void main() int n; printf(please input n(n=0): ); scanf(%d,&n); printf(“%d!=%dn”, n,fac(n); 63int f
39、ac(int n) int t; if (n=0|n=1) t=1; else t=n*fac(n-1); return (t); 在定义递归函数时,通常采用选择结构在定义递归函数时,通常采用选择结构来设计函数,典型的句式是应用来设计函数,典型的句式是应用if语句。通语句。通过判断递归结束条件是否为真,来确定是应过判断递归结束条件是否为真,来确定是应回归求解,还是继续递推。回归求解,还是继续递推。64fac(5)输出输出fac(5)mainf=fac(4)5fac函数函数n=5f=fac(3)4fac函数函数n=4f=fac(1)2fac函数函数n=2f=fac(2)3fac函数函数n=3f=
40、1fac函数函数n=1fac(1)=1fac(2)=2fac(3)=6fac(4)=24fac(5)=12012065u所求解的问题能转化为用同一方法解决的子问题,子问题的规模比原问题的规模小。u必须要有递归结束条件,停止递归,否则形成无穷递归,系统无法实现。u递归结束条件,解决最基本的问题并返回一个明确的结果。u包含递归调用的语句,通过调用函数自身来简化原问题,并使函数参数逐渐逼近递归结束条件。66【例4.9】用递归法计算Fibonacci(斐波拉契)数列的第n项。n费波那西费波那西(Fibonacci)数列数列n特点:第特点:第1、2两个数为两个数为1、1n 从第从第3个数开始,该数是其前
41、面两个数之和个数开始,该数是其前面两个数之和67费波那西费波那西(Fibonacci)数列数列特点:第特点:第1、2两个数为两个数为1、1 从第从第3个数开始,该数是其前面两个数之和个数开始,该数是其前面两个数之和) 3()2(1) 1(12121nFFFnFnFnnn递归递归结束结束条件条件:n=1或或2递归公式如下:递归公式如下:68#includelong fibo(long n);void main() long n; printf(please input n(n=1): ); scanf(%ld,&n); printf(fibo(%ld)=%ldn,n,fibo(n);69
42、long fibo(long n)long t;if (n=1|n=2)t=1;elset=fibo(n-1)+fibo(n-2); return (t); please input n(n=1):10 fibo(10)=5570【例【例4.104.10】HanoiHanoi(汉诺)塔问题。一个古典的数学问(汉诺)塔问题。一个古典的数学问题。题。 有有3 3个柱子个柱子A A,B B,C C。A A柱上套有柱上套有6464个大小不等的圆盘,个大小不等的圆盘,大的在下,小的在上。大的在下,小的在上。 要把这要把这6464个圆盘从个圆盘从A A柱移动到柱移动到C C柱上,每次只能移动柱上,每次只能
43、移动一个圆盘,移动可以借助一个圆盘,移动可以借助B B柱进行。但在任何时候,柱进行。但在任何时候,任何柱子上的圆盘都必须保持大盘在下,小盘在上。任何柱子上的圆盘都必须保持大盘在下,小盘在上。编程打印出移动的步骤。编程打印出移动的步骤。 71ABC72解题思路:解题思路: 要把64个盘子从A柱移动到C柱,需要移动大约264 次盘子。一般人是不可能直接确定移动盘子的每一个具体步骤的。分解为三个步骤分解为三个步骤:(1)将A柱上的n-1个圆盘借助C柱移到B柱上;(2)将A上的一个圆盘移到C柱上;(3)将B柱上的n-1个圆盘借助A柱移到C柱上。73ABC将将63个从个从A到到B第第1个人的做法个人的做
44、法74ABC将将63个从个从A到到B第第1个人的做法个人的做法75ABC将将1个从个从A到到C第第1个人的做法个人的做法76ABC将将1个从个从A到到C第第1个人的做法个人的做法77ABC将将63个从个从B到到C第第1个人的做法个人的做法78ABC将将63个从个从B到到C第第1个人的做法个人的做法79ABC将将1个盘子从个盘子从A移到移到C将将3个盘子从个盘子从A移到移到C的全过程的全过程80ABC将将1个盘子从个盘子从A移到移到C将将3个盘子从个盘子从A移到移到C的全过程的全过程81ABC将将1个盘子从个盘子从A移到移到B将将3个盘子从个盘子从A移到移到C的全过程的全过程82ABC将将1个盘
45、子从个盘子从A移到移到B将将3个盘子从个盘子从A移到移到C的全过程的全过程83ABC将将1个盘子从个盘子从C移到移到B将将3个盘子从个盘子从A移到移到C的全过程的全过程84ABC将将2个盘子从个盘子从A移到移到B的过程的过程将将1个盘子从个盘子从C移到移到B85ABC将将2个盘子从个盘子从B移到移到C的过程的过程86ABC将将2个盘子从个盘子从B移到移到C的过程的过程87ABC将将2个盘子从个盘子从B移到移到C的过程的过程88ABC将将2个盘子从个盘子从B移到移到C的过程的过程89#includevoid Hanoi(int n,char sou, char mid,char tar);voi
46、d main() int n;printf(please input n(n=1): );scanf(%d,&n);Hanoi(n,A,B,C);90void Hanoi(int n,char sou, char mid,char tar) if (n=1) printf(%c-%cn,sou,tar); else Hanoi(n-1,sou,tar,mid); printf(%c-%cn,sou,tar); Hanoi(n-1,mid,sou,tar);n:圆盘数圆盘数sou:源柱源柱mid:借助借助柱柱tar:目的柱目的柱91Please input n(n=1):4 ABAC B
47、C ABCACB ABACBCBACABCABACBC 92 变量的作用域变量的作用域是指一个变量在程序中可以被使用的范围。是指一个变量在程序中可以被使用的范围。1、内部、内部变量变量u在函数和复合语句内定义的变量,称为在函数和复合语句内定义的变量,称为内部变量内部变量或或局部变量局部变量u只在只在本函数或复合语句内本函数或复合语句内范围内有效范围内有效(从定义点从定义点开始到函数或复合语句结束开始到函数或复合语句结束)u在此函数或复合语句以外是不能使用这些变量的在此函数或复合语句以外是不能使用这些变量的93#includeint fun(int a);void main() int a=3,
48、 b; b=a+1; float b=6;printf(%fn,a+b); printf(%dn,a+b); printf(%dn,fun(a);int fun(int a) int m; m=2*a; return (m);a、b的作用域的作用域b的作用域的作用域形参形参a的作用域的作用域m的作用域的作用域94 说明说明: :(1)(1)主函数中定义的变量也只在主函数中有效主函数中定义的变量也只在主函数中有效,主函主函数也不能使用其他函数中定义的变量。数也不能使用其他函数中定义的变量。(2)(2)不同函数中可以使用相同名字的变量不同函数中可以使用相同名字的变量,它们代表它们代表不同的对象不同
49、的对象,互不干扰互不干扰。(3)(3)在一个函数内部在一个函数内部,可以在复合语句中定义变量可以在复合语句中定义变量,这些变量只在本复合语句中有效。这些变量只在本复合语句中有效。(4)(4)当函数调用结束后,内部变量所占内存单元即刻当函数调用结束后,内部变量所占内存单元即刻释放,该变量不可再使用释放,该变量不可再使用。(5)(5)形式参数也是局部变量。在函数中可以使用本函形式参数也是局部变量。在函数中可以使用本函数定义的形参数定义的形参,在函数外不能引用在函数外不能引用它它。95 2、外部、外部变量变量u一个程序可以包含一个或若干个源程序文件(即程序模块),而一个源文件可以包含一个或若干个函数
50、。u在函数之外定义的变量是外部变量外部变量,也称为全局变全局变量量(或全程变量),它不属于任何一个函数,属于一个源程序文件。u外部变量的作用域作用域为从定义变量的位置开始到本源文件结束,在此范围内可以为本文件中所有函数所共用。962、外部、外部变量变量u当外部变量的定义出现在函数定义之前,则函数当外部变量的定义出现在函数定义之前,则函数中可以直接使用该外部变量,而如果外部变量的中可以直接使用该外部变量,而如果外部变量的定义在函数定义之后,则必须先声明该外部变量,定义在函数定义之后,则必须先声明该外部变量,然后才能在函数中使用。然后才能在函数中使用。u外部变量的声明方法为:外部变量的声明方法为:
51、 externextern 类型名类型名 外部变量名;外部变量名;声明外部变量,扩展作用范围。声明外部变量,扩展作用范围。97#includeint a=1;extern int x; int f1() int t; t=x+2*a; x+; return (t);int x=3, y=4;int f2() int t; t=a+x+y; return (t);void main() printf(f1()=%dn,f1(); printf(f2()=%dn,f2();a的的作作用用域域声明外部变量声明外部变量x,y的作用域的作用域x的的作作用用域域y的作用域的作用域98u全局变量在程序的全部
52、执行过程中都占用存储单元,而不是仅在需要时才开辟单元。u使用全局变量过多,会降低程序的清晰性。在各个函数执行时都可能改变外部变量的值,程序容易出错。u它降低函数的通用性,因为函数在执行时要依赖于其所在的外部变量。如果将一个函数移到另一个文件中,还要将有关的外部变量及其值一起移过去。建议不在必要时不要使用全局变量,原因如下:建议不在必要时不要使用全局变量,原因如下: 993、作用域规则、作用域规则u在程序中,可能会出现变量同名的情况。在程序中,可能会出现变量同名的情况。uC语言中,对于同名变量的处理应遵循下面的规则:语言中,对于同名变量的处理应遵循下面的规则:(1)在同一个作用域内不允许出现同名
53、变量的定义。在同一个作用域内不允许出现同名变量的定义。(2)相互独立的两个作用域内的同名变量分配不同相互独立的两个作用域内的同名变量分配不同的存储单元,代表不同的变量,互不影响。的存储单元,代表不同的变量,互不影响。(3)如果在一个作用域和其所包含的子作用域内出如果在一个作用域和其所包含的子作用域内出现同名变量,则在子作用域中,内层变量有效,现同名变量,则在子作用域中,内层变量有效,外层变量被屏蔽。外层变量被屏蔽。100#include int d=1; void f1(int m);void f2(int n); void main() int a=3; f1(a); f2(a); d+=a
54、; printf(d=%dn, d); void f1(int m) int d=5; d+=m; printf(d=%dn, d); void f2(int n) d+=n; printf(d=%dn, d); 此处此处d外部变量外部变量定义外部变量定义外部变量定义内部变量定义内部变量此处此处d内部变量内部变量此处此处d外部变量外部变量程序运行结果:程序运行结果:d=8d=4d=7101 C语言中,语言中,变量的属性变量的属性有两种:数据类型和存储类别。有两种:数据类型和存储类别。 数据类型数据类型描述的是数据的存储格式和运算规则,如整描述的是数据的存储格式和运算规则,如整型、字符型等。型、
55、字符型等。 存储类别存储类别则描述了数据的作用域和生存期。则描述了数据的作用域和生存期。 作用域作用域描述变量的使用范围,描述变量的使用范围,生存期生存期则描述的是当程则描述的是当程序执行时变量的存在时间。序执行时变量的存在时间。 102变量的变量的生存期生存期:指在程序执行过程中,变量何时被分:指在程序执行过程中,变量何时被分配存储空间,何时被回收空间。即,配存储空间,何时被回收空间。即,变量值存在的变量值存在的时间时间。变量的两种变量的两种存储方式存储方式:静态存储方式和动态存储方式:静态存储方式和动态存储方式静态存储静态存储是指在程序运行期间是指在程序运行期间,为变量分配,为变量分配固定
56、固定的存储空间的存储空间。动态存储动态存储是在程序运行期间是在程序运行期间,根据需要根据需要为变量为变量动动态态地地分配存储空间分配存储空间。103 C语言变量的存储类别可以分为:语言变量的存储类别可以分为: 自动变量(自动变量(auto)、静态变量()、静态变量(static)、寄存器)、寄存器变量(变量(register)、外部变量()、外部变量(extern)。)。定义变量的格式为:定义变量的格式为: 存储类别存储类别 数据类型数据类型 变量名;变量名;例如例如: auto int x; static float m;104uautoauto变量又称自动变量,属于动态存储类别。变量又称自
57、动变量,属于动态存储类别。 u函数中定义的函数中定义的内部变量内部变量、形参形参和和复合语句中定义的复合语句中定义的变量变量都属于自动变量。都属于自动变量。u在调用该函数时,系统给这些变量分配存储空间,在调用该函数时,系统给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间。因此在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为这类局部变量称为自动自动变量。变量。u每一次执行到定义自动变量的语句时,系统都会为每一次执行到定义自动变量的语句时,系统都会为它们在内存中分配新的内存空间,并对它们重新进它们在内存中分配新的内存空间,并对它们重新进行初始化。行初始化。 105自动变量
58、用关键字自动变量用关键字autoauto作存储类别的声明作存储类别的声明。 auto int i=1; 内部变量的默认存储类内部变量的默认存储类别为别为auto,可以省略可以省略等价等价int i=1;106#includevoid fun();void main() auto int i; for(i=1;i=4;i+) fun(); void fun() auto int i=0; i+; printf(i have been called %d times.n, i);声明声明i为自动变量为自动变量声明声明i为自动变量为自动变量程序运行结果:程序运行结果:i have been call
59、ed 1 times.i have been called 1 times.i have been called 1 times.i have been called 1 times.107u当希望函数中的内部变量在函数调用结束后依然存当希望函数中的内部变量在函数调用结束后依然存在,并在下一次调用函数时,该在,并在下一次调用函数时,该变量仍然保留上一变量仍然保留上一次函数调用结束时的值次函数调用结束时的值,则可以将该变量的存储类,则可以将该变量的存储类别声明为别声明为static。u静态变量的生存期和程序的生存期一致。当程序被静态变量的生存期和程序的生存期一致。当程序被编译时,就为静态变量在内
60、存中分配存储单元,并编译时,就为静态变量在内存中分配存储单元,并初始化赋值。整个程序运行期间,静态变量一直占初始化赋值。整个程序运行期间,静态变量一直占用存储单元,并且不再重新初始化。当程序运行结用存储单元,并且不再重新初始化。当程序运行结束时,静态变量的存储单元才会被释放。束时,静态变量的存储单元才会被释放。108#includeint fac(int n);void main( )int i;for(i=1; i=5; i+) printf(%d!=%dn, i, fac(i); int fac(int n)static int f=1;f=f*n;return f;声明声明f为静态变量为静态变量程序运行结果:程序运行结果:1!=12!=23!=64!=245!=120每调用一次,开每调用一次,开辟新辟新n,但,但f不是不是109u若初始化时若初
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 不能玩火教案反思
- 海岛冰轮初转腾说课稿
- 农忙季节临时帮工合同
- 通信设备公司人才引进合同样板
- 车辆报废回收企业管理办法
- 通信工程配电房建设协议
- 人力资源服务审批指南
- 网络应急演练
- 设备买卖合同签订预付款政策
- 肌腱断裂术后护理及功能锻炼
- 人教版九年级上册 第七单元 燃料及其利用 课题一 燃烧及灭火 说课稿 (讲学稿)
- 数列部分单元教学设计
- 人教版八年级数学上册《幂的运算》专项练习题-附含答案
- 小学劳动教育四年级下册第一单元 3 《缝沙包》课件
- 软件工程师生涯人物访谈报告
- 山东省青岛市即墨区2023-2024学年九年级上学期期中英语试卷
- 六年级科学上册工具与技术3.3不简单的杠杆优盐件教科版
- 瘾疹的护理查房
- 海南省门诊慢性特殊疾病认定表
- 家长会课件:六年级上学期家长会课件
- 村(居)民房屋翻建(新建)申请表
评论
0/150
提交评论