收藏 分享(赏)

c语言char8_A.ppt

上传人:hwpkd79526 文档编号:9434431 上传时间:2019-08-07 格式:PPT 页数:57 大小:333.50KB
下载 相关 举报
c语言char8_A.ppt_第1页
第1页 / 共57页
c语言char8_A.ppt_第2页
第2页 / 共57页
c语言char8_A.ppt_第3页
第3页 / 共57页
c语言char8_A.ppt_第4页
第4页 / 共57页
c语言char8_A.ppt_第5页
第5页 / 共57页
点击查看更多>>
资源描述

1、第4章 函 数,C语言是通过函数来实现模块化程序设计的。所以较大的C语言应用程序,往往是由多个函数组成的,每个函数分别对应各自的功能模块。函数的定义与调用函数的嵌套调用与递归调用内部变量与外部变量内部函数与外部函数变量的动态存储与静态存储,函数的定义与调用,函数的定义 函数的返回值与函数类型 对被调用函数的说明和函数原型 函数的调用 函数的形参与实参,函数的定义,1任何函数(包括主函数main())都是由函数说明和函数体两部分组成。根据函数是否需要参数,可将函数分为无参函数和有参函数两种。 (1)无参函数的一般形式函数类型 函数名(void) 说明语句部分;可执行语句部分; 如: int fu

2、nc() 注意:在旧标准中,函数可以缺省参数表。但在新标准中,函数不可缺省参数表;如果不需要参数,则用“void”表示,主函数main()例外。,void func( )printf(“*n“);printf(“printed in funcn“);printf(“*n“); main()func();printf(“this is printed in mainn“); ,例程func0_b.c,(2)有参函数的一般形式 函数类型 函数名( 数据类型 参数,数据类型 参数2 ) 说明语句部分;可执行语句部分; 例: int func(int a,int b) 有参函数比无参函数多了一个参数表

3、。调用有参函数时,调用函数将赋予这些参数实际的值。 为了与调用函数提供的实际参数区别开,将函数定义中的参数表称为形式参数表,简称形参表。,int add(int x,int y)int sum;sum = x+y;return sum; main()int a,b,c;scanf(“%d,%d“, ,例程func_b.c,案例 定义一个函数,用于求两个数中的较大数。/*功能:定义一个求较大数的函数并在主函数中调用*/ int max(int n1, int n2) return (n1n2?n1:n2); main( )int max(int n1, int n2); /*函数说明*/int

4、num1,num2;printf(“input two numbers:n“);scanf(“%d,%d“, /*使程序暂停,按任一键继续*/,例程func.c,2说明 (1)函数定义不允许嵌套。 在语言中,所有函数(包括主函数main())都是平行的。一个函数的定义,可以放在程序中的任意位置,主函数main()之前或之后。但在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。 (2)空函数:既无参数、函数体又为空的函数。其一般形式为:函数类型 函数名(void) (3)在老版本C语言中,参数类型说明允许放在函数说明部分的第2行单独指定。,int max(x,y) int x,y; ,

5、例程func9.c,函数的形参与实参及程序的执行顺序,函数的参数分为形参和实参两种,作用是实现数据传送。 形参出现在函数定义中,只能在该函数体内使用。发生函数调用时,调用函数把实参的值复制1份,传送给被调用函数的形参,从而实现调用函数向被调用函数的数据传送。 案例3 实参对形参的数据传递。(注意执行顺序),void main()void s(int n); /*说明函数*/int n=100; /*定义实参n,并初始化*/s(n); /*调用函数*/*输出调用后实参的值,便于进行比较*/printf(“n_first=%dn“,n); void s(int n)int i;printf(“n_

6、begin=%dn“,n); /*输出改变前形参的值*/for(i=n-1; i=1; i-) n=n+i; /*改变形参的值*/printf(“n_end=%dn“,n); /*输出改变后形参的值*/ ,例程func2.c,说明: (1)实参可以是常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此,应预先用赋值、输入等办法,使实参获得确定的值。 (2)形参变量只有在被调用时,才分配内存单元;调用结束时,即刻释放所分配的内存单元。因此,形参只有在该函数内有效。调用结束,返回调用函数后,则不能再使用该形参变量。 (3)实参对

7、形参的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 (4)实参和形参占用不同的内存单元,即使同名也互不影响。,函数的返回值与函数类型,语言的函数兼有其它语言中的函数和过程两种功能, 从这个角度看,又可把函数分为有返回值函数和无返回 值函数两种。 1函数返回值与return语句 有参函数的返回值,是通过函数中的return语句来获得的。 (1)return语句的一般格式: return ( 返回值表达式 ); (2)return语句的功能:返回调用函数,并将“返回值表达式”的值带给调用函数。 注意:调用函数中无return语句,并不是不返回一个值,而是一个不确

8、定的值。为了明确表示不返回值,可以用“void”定义成“无(空)类型”。,2函数类型 在定义函数时,对函数类型的说明,应与return语句中、返回值表达式的类型一致。 如果不一致,则以函数类型为准。如果缺省函数类型,则系统一律按整型处理。 良好的程序设计习惯:为了使程序具有良好的可读性并减少出错,凡不要求返回值的函数都应定义为空类型;即使函数类型为整型,也不使用系统的缺省处理。,对被调用函数的说明和函数原型,在ANSI C新标准中,采用函数原型方式,对被调用函数进行说明,其一般格式如下:函数类型 函数名(数据类型 参数名, 数据类型 参数名2);语言同时又规定,在以下几种情况下,可以省去对被调

9、用函数的说明:(1)当被调用函数的函数定义出现在调用函数之前时。因为在调用之前,编译系统已经知道了被调用函数的函数类型、参数个数、类型和顺序。(2)如果在所有函数定义之前,在函数外部(例如文件开始处)预先对各个函数进行了说明,则在调用函数中可缺省对被调用函数的说明。(3) 如果被调函数的返回值是整型或字符型时, 可以不对被调函数作说明,而直接调用。这时系统将自动对被调函数返回值按整型处理。(4) 对库函数的调用不需要再作说明, 但必须把该函数的头文件用include命令包含在源文件前部。,例程func8.c,函数的调用,语言中,函数调用的一般形式为: 函数名(实际参数表) 切记:实参的个数、类

10、型和顺序,应该与被调用函数所要求的参数个数、类型和顺序一致,才能正确地进行数据传递。 在语言中,可以用以下几种方式调用函数: (1)函数表达式:函数作为表达式的一项,出现在表达式中,以函数返回值参与表达式的运算。这种方式要求函数是有返回值的。 (2)函数语句:C语言中的函数可以只进行某些操作而不返回函数值,这时的函数调用可作为一条独立的语句。 (3)函数实参:函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的。,说明: (1)调用函数时,函数名称必须与具有该功能的自定义函数名称完全一致。 (2)实参在类型上按顺序与形参,必须一一对应

11、和匹配。如果类型不匹配,C编译程序将按赋值兼容的规则进行转换。如果实参和形参的类型不赋值兼容,通常并不给出出错信息,且程序仍然继续执行,只是得不到正确的结果。 (3)如果实参表中包括多个参数,对实参的求值顺序随系统而异。有的系统按自左向右顺序求实参的值,有的系统则相反。Turbo C和MS C是按自右向左的顺序进行的 。,main()int i = 0;printf(“%d , %d , %d n“,i,i+,+i); TC中,函数的实参是从右向左求的。,例程func1.c,函数的嵌套调用和递归调用,函数的嵌套调用是指,在执行被调用函数时,被调用函数又调用了其它函数。这与其它语言的子程序嵌套调

12、用的情形是类似的,其关系可表示如图4-2。,例 计算s=1k+2k+3k+N k /*功能:函数的嵌套调用*/ #define K 4 #define N 5 long f1(int n,int k) /*计算n的k次方*/ long power=n; int i; for(i=1;ik;i+) power *= n; return power; ,long f2(int n,int k) /*计算1到n的k次方之累加和*/long sum=0;int i;for(i=1;i=n;i+) sum += f1(i, k);return sum; main( ) int total =0;prin

13、tf(“Sum of %d powers of integers from 1 to %d = “,K,N);total = f2(N,K);printf(“%dn”,total); /* printf(“%dn“,f2(N,K);*/ ,例程func3.c,嵌套调用的执行过程,main( )int total=0;printf(“”);total= f2(N,K);printf(total); ,f2(n,k)long sum=0;int i;for() sum+=f1(i,k);return sum; ,f1(n,k)long power=n;int i;for() power*=n;re

14、turn power; ,函数的递归调用,函数的递归调用是指:一个函数在它的函数体内,直接或间接地调用它自身。 语言允许函数的递归调用。在递归调用中,调用函数又是被调用函数,执行递归函数将反复调用其自身。每调用一次就进入新的一层。 为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。,递归举例,例 编程计算n!。 /*功能:通过函数的递归调用计算阶乘*/ /* 基本思路: n!=n*(n-1)! */ long power(int n) long f;if(n1) f=power(n-1)*n;else f=1;

15、return(f); ,main( ) int n;long y;printf(“input a inteager number:n“);scanf(“%d“, ,例程func4.c,递归的执行过程,main( )y=power(3);printf(y); ,第一次调用 power(3 ) if(n1) f=power(n-1)*n; else f=1; return(f); /* n=3 */,第二次调用 power(2 ) if(n1) f=power(n-1)*n; else f=1; return(f); /* n=2 */,第二次调用 power(1 ) if(n1) f=power

16、(n-1)*n; else f=1; return(f); /* n=1 */,变量的作用域(局部变量与全局变量),语言中所有的变量都有自己的作用域。变量说明的位置不同,其作用域也不同,据此将语言中的变量分为局部变量和全局变量。在一个函数内部定义的变量,只在本函数范围内有效,这样的变量称为本函数的局部变量。定义在函数外部的变量,该变量不属于任何一个函数,但可被本程序中其它函数所共用,它的有效范围是从定义开始到本源程序结束,该类变量称为全局变量。,说出下面程序中的变量类型及其作用域,int p=1,q=5; int f1(int a) int i=2; a=a*i;printf(“i=%d,a=

17、%d,p=%d,q=%d in f1n“,i,a,p,q); float x=2.5,y=3; int f2(char a)char b= B; p=p+a;q=q+b;printf(“b=%c,a=%c,p=%d,q=%d in f2n”,b,a,p,q);printf(”x=%6.2f,y=%6.2f in f2n“,x,y); main( ) int k=6; f1(k); f2(A);printf(“p=%d,q=%d,x=%6.2f,y=%6.2f in mainn”,p,q,x,y); ,例程func6.c,关于局部变量的作用域还要说明以下几点:,1主函数main()中定义的内部变

18、量,也只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的内部变量。因为主函数也是一个函数,与其它函数是平行关系。这一点是与其它语言不同的,应予以注意。 2形参变量也是内部变量,属于被调用函数;实参变量,则是调用函数的内部变量。 3允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。 4在复合语句中也可定义变量,其作用域只在复合语句范围内。 (例程func6.c),变量的存储类型,在语言中,对变量的存储类型说明有以下四种:自动变量(auto)、寄存器变量(register)、外部变量(extern)、静态变量(static

19、)。这四种类型的变量在程序运行期间根据所分配地址的变化与否,又可分为动态变量(自动变量和寄存器变量)和静态变量(外部变量和静态内部变量)。动态存储变量是指在程序运行中根据需要动态分配存储空间的变量;静态存储变量指在程序运行中所分配的存储空间固定的变量。,变量存储类型的说明,局部变量的存储方式 (1)不做专门说明时默认为auto 型:该类型变量位于动态存储区,离开函数其值就消失。 (2)用static说明的局部静态变量:该类型变量位于静态存储区,默认初始值为0,该类变量,离开函数它们的值仍保留,直到程序结束。 (3)用register说明的变量:位于cpu的寄存器中,能够提高执行效率,离开函数其

20、值就消失。,内部变量的存储方式,1静态存储静态内部变量 (1)定义格式: static 数据类型 内部变量表; (2)存储特点 1)静态内部变量属于静态存储。在程序执行过程中,即使所在函数调用结束也不释放。换句话说,在程序执行期间,静态内部变量始终存在,但其它函数是不能引用它们的。 2)定义但不初始化,则自动赋以“(整型和实型)或0(字符型);且每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值! (3)何时使用静态内部变量 1)需要保留函数上一次调用结束时的值。 2)变量只被引用而不改变其值。,2动态存储自动局部变量(又称自动变量) (1)定义格式:auto 数据类型 变量

21、表; (2)存储特点 1)自动变量属于动态存储方式。在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束就释放。 在复合语句中定义的自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,否则将引起错误。 2)定义而不初始化,则其值是不确定的。 3)由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名。建议:系统不会混淆,并不意味着人也不会混淆,所以尽量少用同名自动变量!,3寄存器存储寄存器变量 一般情况下,变量的值都是存储在

22、内存中的。为提高执行效率,语言允许将局部变量的值存放到寄存器中,这种变量就称为寄存器变量。定义格式如下:register 数据类型 变量表; (1)只有局部变量才能定义成寄存器变量,即全局变量不行。 (2)对寄存器变量的实际处理,随系统而异。例如,微机上的MSC和TC 将寄存器变量实际当作自动变量处理。 (3)允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。,试写出程序的执行结果,main()auto int a=2; register int b=2; static int c=2;printf(“*a=%d,b=%d,c=%d n”,a,b,c);f(a);f(b);f(c);

23、printf(“*a=%d,b=%d,c=%d n”,a,b,c); int f(int x)auto int a= 10; register int b=20; static int c;a=a+x; b=b-x; c=c+x*x;printf(“a=%d, b=%d,c=%d n”,a,b,c); ,*a=2,b=2,c=2 a=12,b=18,c=4 a=12,b=18,c=8 a=12,b=18,c=12 *a=2,b=2,c=2,例程func7.c,全局(外部)变量,全局变量定义在函数之外,能被其它函数所共享。其作用域是从定义点到本文件结束。如果定义点之前的函数需要引用这些外部变量时

24、,需要在函数内对被引用的外部变量进行说明。外部变量说明的一般形式为:extern 数据类型 外部变量,外部变量2;当一个程序由多个源文件组成时,而这多个源文件需要公用一个变量(全局)时,则可在一个源文件中定义,然后可用上述说明方法(extern)在其它需要使用变量的源文件中声明。如:,P1.c文件中 #include “p2.c” int a; main( ) ,P2.c文件中 extern int a; Power(int n) ,例程func10.c func101.c,对于全局变量及存储方式还有以下几点说明:,(1)外部变量可加强函数模块之间的数据联系,但又使这些函数依赖这些外部变量,因

25、而使得这些函数的独立性降低。 从模块化程序设计的观点来看这是不利的,因此不是非用不可时,不要使用外部变量。 (2)在同一源文件中,允许外部变量和内部变量同名。在内部变量的作用域内,外部变量将被屏蔽而不起作用。 (3)全局变量都是静态保存,用static定义全局变量时,此变量将只能被在本文件中的函数使用,而不能在别的文件中使用。即有利于限制变量的作用域。注意:外部变量的定义和外部变量的说明是两回事。外部变量的定义,必须在所有的函数之外,且只能定义一次。而外部变量的说明,出现在要使用该外部变量的函数内,而且可以出现多次。在函数内的extern变量说明,表示引用本源文件中的外部变量!而函数外(通常在

26、文件开头)的extern变量说明,表示引用其它文件中的外部变量。,静态局部变量和静态外部变量同属静态存储方式,但两者区别较大: (1)定义的位置不同。静态局部变量在函数内定义,静态外部变量在函数外定义。 (2)作用域不同。静态局部变量属于内部变量,其作用域仅限于定义它的函数内;虽然生存期为整个源程序,但其它函数是不能使用它的。 静态外部变量在函数外定义,其作用域为定义它的源文件内;生存期为整个源程序,但其它源文件中的函数也是不能使用它的。(3)初始化处理不同。静态局部变量,仅在第1次调用它所在的函数时被初始化,当再次调用定义它的函数时,不再初始化,而是保留上1次调用结束时的值。而静态外部变量是

27、在函数外定义的,不存在静态内部变量的“重复”初始化问题,其当前值由最近1次给它赋值的操作决定。,务必牢记:把局部变量改变为静态内部变量后,改变了它的存储方式,即改变了它的生存期。把外部变量改变为静态外部变量后,改变了它的作用域,限制了它的使用范围。因此,关键字“static”在不同的地方所起的作用是不同的。,C语言程序的一般结构,C程序可由多个源文件组成,每个源文件由予编译命令、函数组成,每个函数由函数首部和函数体组成,每个函数体由说明部分和执行部分(语句)组成。如下:,P1.c文件 #include “p2.c” #include “stdio.h” #defin price 30 int

28、a; main( ) int x,y; ,P2.c文件 #include “stdio.h” extern int a; Power(int n) int y;return y; ,编译预处理,C语言提供编译预处理的功能,允许在程序中使用几种特殊的命令,以供编译预处理,然后将预处理的结果和源程序一起再进行通常的编译处理。 C提供的三种编译预处理处理功能: 1:宏定义 2:文件包含 3:条件编译,宏定义,不带参数的宏定义 带参数的宏定义 带参数的宏定义和函数的区别 宏定义的优点,不带参数的宏定义,格式: #define 标示符 字符串功能: 用宏名(标示符)代替字符串例: #define PI

29、3.14说明: 1: 宏名一般用大写字母. 如:#define PI 3.14 2: 宏定义不是C语句,行末不加分号,若加分号,则连分号一起置换.如: #define PI 3.14; 3: define命令出现在程序中函数的外面,宏名的有效范围是:定义命令之后到本源文件结束,通常写在文件开头. 可以用#undef命令终止宏定义的作用域. 如:#define PI 3.14main( )#undef PI,4:可以引用已定义的宏名,如:#define PI 3.14#define R 3.0#define AREA PI*R*Rmain( ) printf(“The area is %dn“,

30、AREA); 5: 双引号中的area不置换,带参数的宏定义,格式: #define 宏名(参数表) 字符串 功能: 用宏名代替字符串,并且进行参数替换 #define PI 3.14 #define S(r) PI*r*r main( ) float a,area; scanf(“%f“, .,带参数的宏定义说明,:对area=S(a+b)之类, 带入结果: area=PI*a+b*a+b改为: #define S(r) PI*(r)*(r) 则 area=PI*(a+b)*(a+b)2:宏定义时宏名和括号之间不能有空格如: define s (r) PI*r*r ,系统以为用s 代替 (r

31、) Pi*r*r ,带参数的宏定义和函数的区别,函数 先求出实参表达式的值然后带入形参 在程序运行时处理分配临时的工作单元 形参和实参都要定义类型,而且类型要求一致 占运行时间 较复杂的模块用函数较好 不使源程序变长,宏 只是进行简单的字符替换 编译时进行,不分配内存单元,不进行值的传递处理,也没返回值的概念 宏名无类型,参数无类型,只是一个符号代表 占编译时间,不占运行时间 用宏来代表简短的表达式比较合适 展开后使源程序变长,带参数的宏定义和函数的区别举例,函数 main( )int a,b,c,d,t;a=2;b=3;c=1;d=5;t=max(a+b,c+d);printf(“%d“,t

32、); max(x,y) int x,y; return(xy?x:y); ,宏 #define MAX(x,y) (x)(y)?(x):(y) main( )int a,b,c,d,t;a=2;b=3;c=1;d=5;t=MAX(a+b,c+d);printf(“%d“,t); .,例程func11.c func12.c,宏定义的优点,可以简化程序, 方便修改等。#define PRINT(v) printf(“v=%dt“,v)main( ) int a,b,c,d;a=1;b=2;c=3;d=4;PRINT(a);PRINT(b);PRINT(c);PRINT(d); ,文件包含处理,文件

33、包含概念 头文件概念 头文件使用举例 头文件使用说明,文件包含的概念,含义:一个源文件可以将另一个源文件的全部内容包含进来 实现方法:#include “ 文件名“ 例如:程序file1.c,#include “file2.c“,A,A,file2.c,头文件,使用场合:#include “头文件h“ 优点:可以减少程序员的重复劳动。 .,头文件使用举例,主程序: #include “p.h“ main( )float r,area,l;r=3;area=S(r);l=2*PI*r;PRINT(r);PRINT(area);PRINT(l); .,头文件:p.h #include #defin

34、e PI 3.14 #define S(a) PI*(a)*(a) #define PRINT(v) printf(“v=%ft“,v),例程func13.c,头文件说明,1:一个include命令只能指定一个被包含文件,若要包 含n个,则要用n个include 2:文件包含格式有两种:include file3.h 在标准路径下找#include “file2.h“ 可以指定路径 3:在一个包含文件中又可以包含另一个被包含文件,即文件包含可以嵌套 4:若在file1.c中 include “file3.h“#include “file2.h“ 则file1.c和file2.h都可用file3

35、.h中内容,头文件说明举例,func14.c文件: /* #include “func14_2.c“ */ #include “func14_1.c“ main( ) extern f1( );f1( ); ,func14_1.h文件:#include “func14_2.h“ f1( )printf(“In f1( )n“);f2( ); func14_2.h文件:f2( ) printf(“In f2( )n“); ,例程func14.c fucn15.c max1.c order.c,条件编译,条件编译:对于一组语句,当条件满足时才进行编译。 C语言的条件编译命令有: 三种形式,#ifd

36、ef 标示符程序段 else 程序段 #endif,#define IBM-PC 0 #ifdef IBM-PC #define INTEGER_SIZE 16 #else #define INTEGER_SIZE 32 #endif main( )printf(“%dn“,INTEGER_SIZE);,形式一:,例程func16.c,条件编译命令的形式二,#ifndef 标示符程序段 else 程序段 #endif,#define IBM-PC 0 #ifndef IMB-PC #define INTEGER_SIZE 16 #else #define INTEGER_SIZE 32 #endif main( )printf(“%dn“,INTEGER_SIZE); ,例程func17.c,条件编译命令的形式三,#if 表达式程序段 else 程序段 #endif,#include “stdio.h“ #define UPCASE 1 main( )char c; clrscr();while(c=getchar()!=n)#if UPCASEif (c=a ,例程func18.c,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报