计算机软件技术基础 第9章 函数.ppt_第1页
计算机软件技术基础 第9章 函数.ppt_第2页
计算机软件技术基础 第9章 函数.ppt_第3页
计算机软件技术基础 第9章 函数.ppt_第4页
计算机软件技术基础 第9章 函数.ppt_第5页
已阅读5页,还剩52页未读 继续免费阅读

下载本文档

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

文档简介

1、第九章 函数,第九章 函数,9.1 模块化程序设计与函数,在C程序设计中,子程序的作用是用函数来完成的。一个C程序一般由多个函数组成,其中必须有一个且仅有一个名为main的主函数,其余为被main函数或其它函数调用的函数,无论main函数位于程序中什么位置, C程序总是从main函数开始执行。main函数可调用其它函数来实现所需的功能。,第九章 函数,例9.1定义一个函数,用于求两个数中的大数。 main() int max(int n1,int n2); /*声明max()函数*/ int num,num1,num2; printf(Input two integer numbers:n);

2、 scanf(%d,%d,&num1,&num2); num=max(num1,num2); /*调用max()函数*/ printf(max=%dn, num); int max(int n1,int n2) /*定义max()函数*/ return (n1n2?n1:n2); 程序运行情况如下:Input two integer numbers: 12 ,34 max=34,9.1 模块化程序设计与函数,第九章 函数,例9.2输出一个文本信息框。 void fun1 ( ) /*定义fun1()函数*/ printf(* * * * * * * * * * * * * *n); void

3、fun2 ( ) /*定义fun2()函数*/ printf(* How do you do! *n); main() fun1(); /*调用fun1()函数*/ fun2(); /*调用fun2()函数*/ fun1(); /*再次调用fun1()函数*/ 程序运行结果如下: * * * * * * * * * * * * * * * How do you do! * * * * * * * * * * * * * * *,9.1 模块化程序设计与函数,第九章 函数,9.2 函数的定义与调用一、函数的定义,1无参函数定义的一般形式: 类型名 函数名( ) 声明部分; 执行部分; 无参函数没

4、有参数,因此,函数首部的“参数定义表”可以缺省(但括号不能缺省)。,第九章 函数,2有参函数定义的一般形式: 类型名 函数名(类型名 参数名1,类型名 参数名2,.,) 说明部分; 执行部分; 有参函数在其参数定义表中定义了所需的每一个参数的类型和名称。每一个参数单独定义,参数定义之间用逗号隔开。,9.2 函数的定义与调用一、函数的定义,第九章 函数,自定义函数说明部分定义的参数称为形式参数,简称形参。 主调函数提供的参数称为实际参数,简称实参。 函数若无返回值,则其首部的类型标识符用“void”表示。,9.2 函数的定义与调用一、函数的定义,第九章 函数,说明: (1) 除main()函数外

5、,函数名和形参名都是由用户命名的标识符,要求符合标识符的命名规则。 (2) 函数定义不允许嵌套。在语言中,所有函数(包括主函数main( )都是平行的。在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。 (3) 可以定义空函数。所谓空函数,是指既无参数又无函数体的函数。,9.2 函数的定义与调用一、函数的定义,第九章 函数,其一般形式为:void 函数名( ) (4) 在旧版本的语言中,参数定义表允许放在函数首部的第二行单独指定。 (5) 当一个源程序由多个函数构成时,必须有一个唯一的main()函数。main()函数在源程序中的位置可以任意,程序的执行总是从main()函数开始,最

6、终从main()函数结束。,9.2 函数的定义与调用一、函数的定义,第九章 函数,1形参与实参的参数传递 形参在函数首部定义,必须是变量形式,只能在该函数体内使用。 实参在函数调用表达式中提供,可以是表达式形式。 函数调用时,主调函数把实参的值复制一份,传送给被调用函数的形参变量,从而实现主调函数向被调用函数的参数传递。,9.2 函数的定义与调用二、函数的参数与函数的返回值,第九章 函数,9.2 函数的定义与调用二、函数的参数与函数的返回值,例9.3求两数中值较大的一个数。 int max(int x, int y) if(xy) return x; else return y; main(

7、) int a, b, c; scanf(“%d%d”,&a,&b); c=max(a,b); printf(“max=%dn”,c); 运行结果: 23 45 max=45,第九章 函数,关于形参与实参的说明: (1) 实参可以是常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此,应预先用赋值、输入等方法,使实参获得确定的值。 (2) 形参变量只有在被调用时,才分配存储单元,调用结束后,即刻释放所分配的存储单元。因此,形参只有在该函数内有效。调用结束,返回主调函数后,则不能再使用该形参变量。 (3) 实参对形参的数据传送

8、是单向的值传递,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。,9.2 函数的定义与调用二、函数的参数与函数的返回值,第九章 函数,例9.4分析以下程序能否交换主函数中 a 与 b 的值。 void swap(int x, int y) int t; t=x; x=y; y=t; main() int a=10; b=20; swap(a,b); printf(a=%d,b=%dn,a,b); 程序运行结果如下: a=10, b=20,9.2 函数的定义与调用二、函数的参数与函数的返回值,第九章 函数,2函数的返回值与函数类型 函数的返回值就是调用函数求得的函数值。 1)函数返

9、回值与return语句 函数的返回值是通过函数中的return语句来获得的。 格式:return 表达式; 或 return (表达式); 或 return ; 功能:返回主调函数,并将“表达式”的值带回给主调函数。,9.2 函数的定义与调用二、函数的参数与函数的返回值,第九章 函数,2)函数类型 函数类型就是函数定义首部的类型名所定义的类型,也就是函数返回值的类型。因此,在定义函数时,无返回值函数的类型定义为void,有返回值函数的类型应与return语句中返回值表达式的类型一致。 当有返回值函数的类型定义与ruturn语句中表达式的类型不一致时,则以函数类型定义为准。对于数值型数据,系统能

10、自动进行类型转换,否则,按出错处理。如果缺省函数类型定义,则系统一律按整型处理。,9.2 函数的定义与调用二、函数的参数与函数的返回值,第九章 函数,1函数调用的一般形式 函数调用的一般形式为: 函数名( 实际参数表) 调用无参函数时,缺省实际参数表,但圆括号不能省略。 实际参数表中的参数可以是常量、变量或表达式。如果实参不止一个,则相邻实参之间用逗号分隔。实参的个数、类型和顺序,应该与被调用函数的形参所要求的个数、类型和顺序一致。,9.2 函数的定义与调用三、函数的调用,第九章 函数,2函数调用的方式 (1)当为void类型时,其调用只能单独作为一个语句出现; (2)当函数类型不为void型

11、时,函数的调用可以出现在同类型常量可以出现的任何地方,如:表达式,输出表,实参表中等。但不能出现在输入表和形参表中。,9.2 函数的定义与调用三、函数的调用,第九章 函数,例9.5求两数中较大数。 int max(int x, int y) if(xy) return x; else return y; main( ) int a, b, c; scanf(“%d%d”,&a,&b); c=max(a,b); /*printf(“max=%dn”,max(a,b);*/ /*调用语句在表达式,或输出表中*/ printf(“max=%dn”,c); ,9.2 函数的定义与调用三、函数的调用,第

12、九章 函数,例9.6求三个数中较大数。 int max(int x, int y) if(xy) return x; else return y; main( ) int a, b, c,d; scanf(“%d%d%d”,&a,&b,&c); d=max(max(a,b),c); /*调用语句在实参表中*/ printf(“max=%dn”,d); ,9.2 函数的定义与调用三、函数的调用,第九章 函数,3对被调用函数的声明 1)对被调用函数的声明 C程序中的一个函数要调用另一个函数时必须具备以下两个条件: a)被调用函数已经存在。若是库函数,系统已经定义,否则需要用户自己定义。 b)在主调

13、函数中对被调用函数先声明,然后才能调用。,9.2 函数的定义与调用三、函数的调用,第九章 函数,2)函数的声明方式 类型声明的一般形式为: 类型名 函数名(类型名,类型名); 类型名 函数名(类型名 参数名 ,类型名 参数名2); 其中,参数的“参数名”可以缺省。 函数原型与函数定义的首部是一致的,各参数的顺序也必须与函数首部定义的一致。但函数声明是单独作为一条说明语句,因此其末尾必须有分号(;)。,9.2 函数的定义与调用三、函数的调用,第九章 函数,说明: (1)语言规定,在以下三种情况下,可以省去对被调用函数的声明: 如果函数的值是整型或字符型,可以不必声明。 当对被调用函数的定义出现在

14、主调函数之前时,可以缺省对被调用函数的声明。 如果在所有函数定义之前,在函数外部(例如源文件开始处)预先对各个被调用函数进行了声明,则在主调函数中可缺省对被调用函数的声明。,9.2 函数的定义与调用三、函数的调用,第九章 函数,(2) 函数定义和函数声明是两个不同的概念。 函数定义是对函数功能的确立,包括定义函数名、函数值的类型、函数参数及其函数体等,它是一个完整的、独立的函数单位。在一个程序中,一个函数只能被定义一次,而且是在其他任何函数之外进行的。 函数声明则是把函数的名称、函数值的类型、参数的个数、类型和顺序通知编译系统,以便在调用该函数时系统对函数名称正确与否、参数的类型、个数及顺序是

15、否一致等进行对照检查。,9.2 函数的定义与调用三、函数的调用,第九章 函数,(3) 对库函数的调用不需要声明,但必须把该库函数的头文件用 #include 命令包含在源文件开始处。,9.2 函数的定义与调用三、函数的调用,第九章 函数,例9.7由键盘输入三个整数,输出绝对值最大者 #include “math.h” main( ) int a, b, c, max; scanf(“%d,%d,%d”,&a,&b,&c); max=find(a,b,c); printf(“max=%dn”,max); find( int x, int y, int z ) int max; max=x; if

16、( abs(max) abs(y) ) max=y; if( abs(max) abs(z) ) max=z; return max; 运行结果: 12,34,9 max=34,9.2 函数的定义与调用三、函数的调用,第九章 函数,例9.8编写程序,计算1!2!3!10!的值。 程序如下: long fact(int n) int i; long s=1; for (i=1; i=n; i) s=s*i; return s; main( ) long s=0; int k,n; printf(“Input a number:”); scanf(%d,&n); for (k=1; k=n; k)

17、 s=sfact(k); printf(1!2!10!=%ldn,n,s); 程序运行情况如下: Input a number:10 1!2!10!=4037914,9.2 函数的定义与调用三、函数的调用,第九章 函数,例9.9用公式求的近似值,直到最后一项的绝对值小于106为止。 #include “math.h” main( ) float cal(float); float pi; pi=cal(1e6); printf(“pi=%10.6f n”,pi); float cal( float e ) int s; float pi,n,t; t=1;pi=0;n=1.0;s=1; whi

18、le( fabs(t) = e ) pi=pit; n=n2; s=s; t=s/n; return pi*4; 运行结果: pi=3.141594,9.2 函数的定义与调用三、函数的调用,第九章 函数,例9.10求100200之间的全部素数之和 #include “math.h” main( ) int m, s=0; for(m=101; m200; m=2) s=sum(m); printf(“s=%dn”,s); sum(int m ) int i, k; k=sqrt(m); for( i=2; i=k; i) if(m%i=0) return 0; return m; 运行结果如下

19、: s=3167,9.2 函数的定义与调用三、函数的调用,第九章 函数,1函数的嵌套调用 在一个函数的执行过程中又调用另一个函数的调用方式称为函数的嵌套调用。 2说明 (1) C语言不允许函数嵌套定义,但允许在一个函数的函数体中出现对另一个函数的调用。所谓函数的嵌套调用,是指在执行被调用函数时,被调用函数又调用了其他函数。,9.3 函数的嵌套调用与递归调用一、函数的嵌套调用,第九章 函数,9.3 函数的嵌套调用与递归调用一、函数的嵌套调用,(2) 图中表示了两层嵌套的情形。其执行过程是:执行main()函数中调用f1()函数的语句时,即转去执行f1()函数;在f1()函数中调用f2()函数时,

20、又转去执行f2()函数;f2()函数执行完毕,返回f1()函数的断点,继续执行其后续语句;f1()函数执行完毕,返回main()函数的断点,继续执行后续语句。,第九章 函数,例9.11求1!2!3!4!.20! main() float sum(int); float add; add=sum(20); printf(“add=%e”,add); float sum(int n) float fac(int); int i; float s=0; for(i=1;i=n;i) s=fact(i); return s; float fac(int i) float t=1; int n=1; d

21、o t=t*n; n;while(n=i); return t; 运行结果为:s=2.56133e18,9.3 函数的嵌套调用与递归调用一、函数的嵌套调用,第九章 函数,例9.12用递归法计算n!。 分析:用递归法计算n!,可用下述公式表示: n!=n*(n1)! (n2) 1!=1 (n=1) long fac(int n) long c; if (n1) c=fac(n1)*n; else f=1; return f; main() int n; long y;printf(“Input a integer number: ”); scanf(“%d”,&n); y=fac(n); pri

22、ntf(%d!=%ldn,n,y); 程序运行情况如下:Input a integer number:5 5!=120,9.3 函数的嵌套调用与递归调用二、函数的递归调用,第九章 函数,说明 (1) 递归函数既是主调函数,同时又是被调用函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层。下图中,函数f()为直接递归函数,函数f1()和函数f2()为间接递归函数。,9.3 函数的嵌套调用与递归调用二、函数的递归调用,第九章 函数,(2) 如果递归函数无休止地调用其自身,这当然是不正确的。为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的办法是加条件判断,满足某种条件

23、后就不再作递归调用,然后逐层返回。这个条件称为递归结束条件。 (3) 递归算法一般也可以用“递推”的循环结构来代替。也可以用递推法编程。递推法比递归法更容易理解和实现。但是有些问题只能用递归算法才能实现。,9.3 函数的嵌套调用与递归调用二、函数的递归调用,第九章 函数,例9.13用递归法将十进制整数转换为二进制整数。 void fun(int n) if (n/2) fun(n/2); printf(%d,n%2); main() int a; printf(Input a integer number:); scanf(“%d”,&a); fun(a); printf(n); 程序运行情况

24、如下: Input a integer number::345 101011001,9.3 函数的嵌套调用与递归调用二、函数的递归调用,第九章 函数,1局部变量的概念和定义 在一个函数(包括main()函数)内部或复合句内部定义的变量称为局部变量。 函数的形参属于局部变量。局部变量只在该函数范围内或该复合句范围内有效。 2说明 (1) 主函数main()中定义的局部变量,只能在主函数中使用,其他函数不能使用。同时,主函数中也不能使用其他函数中定义的局部变量。因为主函数也是一个函数,与其他函数是平行关系。,9.4 变量的作用域一、局部变量,第九章 函数,9.4 变量的作用域一、局部变量,第九章

25、函数,(2) 形参变量也是局部变量,属于被调用函数;实参变量则是主调函数的局部变量。 (3) C语言允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的存储单元,互不干扰,也不会发生混淆。 (4) 在复合句中也可定义变量,其作用域只在复合句范围内。,9.4 变量的作用域一、局部变量,第九章 函数,1全局变量的概念和定义 在函数外部定义的变量称为全局变量。全局变量不属于任何一个函数,其作用域是:从全局变量的定义位置开始,到本源文件结束为止。全局变量可被作用域内的所有函数直接引用。,9.4 变量的作用域二、全局变量,第九章 函数,2说明 (1) 全局变量可加强函数模块之间的数据联系,

26、但又使这些函数依赖于这些全局变量,因而使得这些函数的独立性降低。从模块化程序设计的观点来看,这是不利的,因此不是非用不可时,不提倡使用全局变量。 (2) 在同一源文件中,允许全局变量和内部变量同名。同名时在内部变量的作用域内,全局变量将被屏蔽而不起作用。,9.4 变量的作用域二、全局变量,第九章 函数,例9.14全局变量与内部变量同名举例。 int a=3,b=5; int max(int a,int b) int c; c=ab?a:b; return c; main() int a=8; printf(“max=%dn”,max(a,b); 程序运行结果如下: max=8,9.4 变量的作

27、用域二、全局变量,第九章 函数,(3) 全局变量的作用域是从定义点开始到本源文件结束为止的。如果定义点之前的函数需要引用这些全局变量,则需要在函数内对被引用的全局变量进行声明。 全局变量声明的一般形式为 extern 类型名 全局变量1 ,全局变量2;,9.4 变量的作用域二、全局变量,第九章 函数,存储类型是指变量在内存中存储的方式。各种变量的作用域不同,就其本质来说是因为变量的存储类型不同。 变量的存储类型分为静态存储和动态存储两大类。 静态存储变量通常是在变量定义时就分配存储单元,并一直保持不释放,直至整个程序运行结束才释放。 动态存储变量是在程序执行过程中,使用它时才分配存储单元,使用

28、完毕立即释放。,9.5 变量的存储类别一、动态存储与静态存储的概念,第九章 函数,对变量的存储类型定义有以下四种:自动变量(auto)、寄存器变量(register)、全局变量(extern)和静态内部变量(static)。 自动变量和寄存器变量属于动态存储方式,全局变量和静态内部变量属于静态存储方式。,9.5 变量的存储类别一、动态存储与静态存储的概念,第九章 函数,1静态存储静态局部变量 静态局部变量的定义格式如下: static 数据类型 局部变量表; 存储特点: (1) 静态局部变量属于静态存储,是在编译时为其分配存储单元的,其生存期为整个程序执行期间。在程序执行过程中,即使所在函数被

29、调用结束也不释放,一直存在。但其他函数不能引用它们。 (2) 静态局部变量是在编译时赋初值的,若定义而不初始化,则自动赋以0。每次调用静态局部变量所在的函数时,不再重新赋初值,只是保留上次调用结束时的值,如下例所示。,9.5 变量的存储类别二、局部变量的存储方式,第九章 函数,例9.15 void f(int c) int a=0; static int b=0; a;b; printf(“%d: a=%d,b=%dn”,c,a,b); main() int i; for( i=1; i=2; i) f (i ); ,9.5 变量的存储类别二、局部变量的存储方式,第九章 函数,说明: (1)当

30、需要保留函数上一次调用结束时的值时,应使用静态局部变量, (2)当变量定义并初始化后只被引用而不改变其值时也可以使用静态局部变量,以避免每次调用时重新赋值。 (3) 由于静态局部变量的作用域与生存期不一致,降低了程序的可读性,因此,除非对程序的执行效率有很大提高外,一般不提倡使用静态变量。,9.5 变量的存储类别二、局部变量的存储方式,第九章 函数,2动态存储自动局部变量(又称自动变量) 自动变量的定义格式如下: auto 数据类型 自动变量表; 存储特点: (1) 自动变量属于动态存储方式。是在函数被调用时为其分配存储单元的,其生存期为函数被调用期间,调用结束就释放。函数的形参也属于此类变量

31、。 在复合语句中定义的自动变量,其生存期为该复合句被执行期间。,9.5 变量的存储类别二、局部变量的存储方式,第九章 函数,(2) 定义而不初始化时,自动变量的值是不确定的。如果定义并初始化,则赋初值操作是在函数被调用时进行的,且每次调用都要重新赋一次初值。 (3) 由于自动变量的作用域和生存期都局限于定义它的个体内(函数或复合句),因此,不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合句中定义的自动变量同名。 注意:系统不会混淆,并不意味着人也不会混淆,所以尽量少用同名自动变量。,9.5 变量的存储类别二、局部变量的存储方式,第九章 函数,3寄存器

32、存储寄存器变量 一般情况下,变量的值都是存储在内存中的。为提高执行效率,语言允许将内部变量的值存放到寄存器中,这种变量称为寄存器变量。 定义格式如下: register 数据类型 变量表; 说明: (1)只有内部变量和形参变量才能定义为寄存器变量,全局变量则不行。,9.5 变量的存储类别二、局部变量的存储方式,第九章 函数,(2)对寄存器变量的实际处理,随系统而异。 (3)允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。一般将函数中使用频率最高的变量定义为寄存器变量,以此提高程序的执行效率。,9.5 变量的存储类别二、局部变量的存储方式,第九章 函数,全局变量分为两种: 静态全局变量:只允许被本源文件中的函数引用。 定义格式:static 数据类型 全局变量表; 非静态全

温馨提示

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

评论

0/150

提交评论