ImageVerifierCode 换一换
格式:PPT , 页数:96 ,大小:423.50KB ,
资源ID:8220810      下载积分:10 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.docduoduo.com/d-8220810.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录   微博登录 

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(第7章函数.ppt)为本站会员(11xg27ws)主动上传,道客多多仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知道客多多(发送邮件至docduoduo@163.com或直接QQ联系客服),我们立即给予删除!

第7章函数.ppt

1、第七章 函数,本章教学目标: 本章主要介绍C语言中函数的定义与调用、函数的参数和返回值、函数间的数据传递方法、数组作为函数参数、函数的递归调用、变量的作用域和存储方式等。通过本章的学习,要求理解函数的概念,掌握函数定义和函数调用的方法,理解函数调用的实质,掌握有参函数的数据传递方法,区分“值传递”与“地址传递”的概念。理解函数递归调用的概念,掌握递归函数设计的一般方法。了解变量存储类别的概念,理解变量的作用域和生成期的概念。掌握模块化程序设计的一般方法与技巧。,本章重点理解函数的概念掌握函数定义和函数调用的方法本章难点理解函数递归调用的概念掌握递归函数设计的一般方法,教学内容: 7.1 函数概

2、述 7.2 变量的作用域和存储方式 7.3 函数间的参数传递 7.4 数组作为函数参数 7.5 函数的嵌套与递归调用 7.6 变量的存储方式 7.7 程序举例,概 述,人们在求解一个问题时,通常采用的是逐步分解、分而治之的方法,即把一个大问题分解成若干个比较易解的小问题,然后分别求解。一个模块化程序就是用高级语言表示的模块化算法。这种程序便于编写、阅读、修改和维护,提高了程序的可靠性,保证了程序的质量。,7.1,模块化程序设计方法,7.1.1,一个较大的程序通常分为若干个子程序模块,每个子程序模块实现一个特定的功能。在C语言中,这些子程序模块是由函数来完成的。一个C程序可由一个主函数和若干个函

3、数组成。程序执行时,从主函数开始,通过主函数调用其他函数,其他函数也可以相互调用。同一个函数可以被一个或多个函数调用。图7-1是程序中函数调用的示意图。,函数调用的例子,#include main() /*主函数main*/ printa(); /*调用printa函数*/ printb(); /*调用printb函数*/ printc(); /*调用printc函数*/ printa() /*定义printa函数*/ printf(“*n”); printb() /*定义printb函数*/ printf(“C program!n”); printa(); /*调用printa函数*/ pr

4、intc() /*定义printc函数*/ printf(“-n“);,例7-1,(1)一个源程序文件由一个或多个函数构成,每个函数完成一个相对独立的任务。一个源程序文件是一个编译单位,即Turbo C系统是以源程序为单位进行编译,而不是以函数为单位进行编译。 (2)一个C程序是由一个或多个源程序文件组成。C程序的执行从main函数开始,调用其他函数后流程返回到main函数,在main函数中结束整个程序的运行。 (3)所有函数在定义时都是相互独立的,他们之间的关系是平行的。一个函数并不从属于另一个函数,也就是说,在一个函数的函数体内,不能再定义另一个函数,即函数不能嵌套定义。函数间可以相互调用

5、,但不能调用main函数。,说 明,(4)从函数定义的角度,函数分为两种:标准函数,即库函数。由系统提供,用户无须定义和说明,只需在程序前包含有该函数原型的头文件,就可在程序中直接使用。如scanf、printf、getchar、putchar、sqrt等都是标准函数。应该说明,不同的C系统提供的库函数的数量和功能不同,当然有一些基本的函数是共同的。用户自己定义的函数。用户根据需要,自己定义的用以完成某种功能的函数。如例7-1中printa、printb和printc等都是用户定义的函数。,说 明,(5)从函数参数的角度,函数分为两种: 无参函数。函数定义、函数说明、函数调用均不带参数。主调函

6、数和被调函数之间不进行参数传递,如例7-1中printa、printb和printc三个都是无参函数。此类函数通常用来完成一组指定的功能,可以返回或不返回函数值,一般不返回函数值居多。 有参函数。函数定义、函数说明时都有参数,称为形式参数(简称形参)。函数调用时必须给出参数,称为实际参数(简称实参)。进行调用时,主调函数把实参的值传递给形参,供被调函数使用,被调函数也可以将值带回来供主调函数使用。,说 明,函数的定义,7.1.2,1.无参函数定义的一般形式 类型说明符 函数名() 说明部分 语句序列 ,其中类型说明符和函数名称为函数头。类型说明符是指该函数值的类型,即函数返回值的类型。函数名是

7、用户自己定义的标识符,函数名后面必须有一对空括号(),里面不能有参数。花括号中的内容称为函数体,由说明部分和语句序列组成。 无参函数一般不需要有返回值,因此可以不指出函数值的类型。也可以将函数值的类型定义为void,即空类型,以确定函数返回时不带回任何值。,说 明,2.有参函数定义的一般形式 类型说明符 函数名(形式参数及形式参数类型说明) 说明部分 语句序列 ,函数的定义,7.1.2,和无参函数的定义相比,有参函数的定义在函数头部分多了形式参数和形式参数类型说明两项内容。形式参数通常简称为形参。形参可以是任何类型的变量,参数间用逗号分隔。在函数调用时,主调函数将赋予这些形式参数以实际值。,说

8、 明,int fun1(int a,int b) int t; t=a+b; return(t); #include main() /*主函数*/ int x,y,z; scanf(“%d,%d”, ,编一函数fun1用来实现将两个整数相加,【例7-3】,程序中定义的函数fun1有两个形参a、b,其类型都是整型。由于函数是带值返回的,且返回值是整型,因此函数的类型就定义为整型。主函数main中调用了函数fun1,x、y是对应的实参,其类型也是整型。 【注意】如果在定义函数时没有指定函数类型,系统会隐含指定函数类型为int型。因此【例7-3】中函数fun1左边的int可以省略不写。,说 明,3.

9、“空函数”的一般形式 类型说明符 函数名() “空函数”没有任何作用,仅仅是起一个名字。,空函数,在老版本C语言中,对形参类型的声明是放在函数定义的第2行,即不在第1行括号内指定形参的类型,而在括号外单独指定。其一般形式: 类型说明符 函数名(形式参数) 形式参数类型说明 说明部分 语句序列 ,4.,对形参声明的传统方式,【例7-3】中fun1的定义可写成: int fun1(a,b) int a,b; int t; t=a+b; return(t); ,通常把这种方法称为传统的对形参的声明方式,而把【例7-3】中定义函数的方法称为现代的方式,这两种用法是等价的,ANSI新标准推荐使用现代的方

10、式,因为它与PASCAL语言中所用的方法类似,说 明,函数的调用,7.1.3,函数调用,就是指主调函数中调用函数的形式和方法。调用流程:当在一个函数中调用另一个函数,程序控制就从主调函数中的函数调用语句转移到被调函数,执行被调函数体中的语句序列,在执行完函数体中所有的语句,遇到return语句或函数体的右花括号“”时,自动返回到主调函数的函数调用语句并继续往下执行,函数调用关系图,图7-2,函数名(实际参数表);在调用函数时,函数名后面圆括号中的参数称为实际参数,通常简称为实参。多个实参彼此间用逗号分隔。实参与形参的个数应相等,类型应一致。如果调用无参函数,则实参表为空,但函数名后的一对园括号

11、“( )”不能省略。,函数调用的一般形式,1.,按函数在程序中出现的位置不同,可分为以下三种调用方式: (1)函数语句 把函数调用作为一个语句。 (2)函数表达式 函数出现在表达式中,以函数的返回值参与表达式的运算。 (3)函数参数 函数作为另一个函数调用的实参。这种情况是把该函数的返回值作为实参进行传递,因此要求该函数必须带值返回。,函数调用的方式,2.,在函数调用时还应注意求值的顺序问题,一般情况下求值顺序是从左到右,但有时不一定。,#include main() int k=1,j; j=f(k,+k); /*函数调用*/ printf(“%dn“,j); int f(int a,int

12、 b) int c=-1; if(ab) c=1; else if(a=b) c=0; return(c); ,函数调用时求值的顺序,【例7-4】,为什么运行结果不是-1呢?这是因为系统在这种情况下,实参求值顺序是从右到左,即相当于f(2,2),所以程序运行结果为0。 这种情况在printf函数中也同样存在,如:printf(“%d,%dn“,k,k+);若k的原值为1,则在Turbo C系统上运行结果为2,1。请读者务必注意,编程时应避免采用这种容易混淆的用法。,分 析,函数的参数和函数的值,7.2,7.2.1 函数的参数 函数的参数有形参和实参两种,形参是出现在函数定义中,在整个函数体内部

13、都有效,离开该函数则无意义。实参是出现在主调函数中,其作用是把实参的值传递给被调函数的形参,从而实现主调函数向被调函数传递数据的功能。在C程序中,用变量作函数的形参时,实参对形参的数据传递是单向的值传递。,说 明,1.函数在没有被调用前,形参不占内存存储单元。只有调用时,系统才给形参分配存储空间。函数调用结束后,形参所占的存储空间被释放。 2.实参可以是常量、变量或表达式,但必须有确定的值。 3.函数调用时,只能把实参的值传递给形参,而不能把形参的值传递给实参。因此,在函数调用过程中,形参值的改变,不会影响主调函数中实参的值。我们称这种传递是单向的“值传递”。 4.形参和实参在类型、个数及顺序

14、上必须保持一致,否则会发生“类型不匹配”错误。,分析下面程序运行结果,int swap(int a,int b) int t; printf(“a=%d,b=%dn“,a,b); t=a;a=b;b=t; printf(“a=%d,b=%dn“,a,b); #include main() int x=3,y=5; swap(x,y); printf(“x=%d,y=%dn“,x,y); ,【例7-5】,swap函数的功能是交换两个参数的值。从上面运行结果可以看出,交换了两个形参变量a和b的值,而main函数中实参x和y的值没有交换,这是因为实参向形参的数据传递是单向的,因而形参值的改变不会影响

15、实参。,swap,函数的返回值,7.2.2,函数的返回值是通过被调函数中的return语句实现的。return语句是程序控制语句,它可用在除主函数外的其它函数中。return语句的一般形式为: return(表达式); 或 return 表达式; 功能:计算表达式的值,并返回给主调函数。在一个函数中允许有多个return语句,但每次调用只执行一个return语句,因此只能返回一个函数值。,1.return语句也可以不带表达式部分 2.如果不需要从被调函数带回确定的函数值,函数可以没有return语句,这时当程序执行到函数体的右括号“”时,则自动返回到主调函数中。 3.函数返回值的类型和函数定义

16、的类型应保持一致。如果两者不一致,以函数定义的类型为准,函数类型决定函数返回值的类型。 4.如果函数的返回值是整型,则在函数定义时可省略类型说明。 5.为了明确表示“不带回值”,可将函数定义为“空类型”,类型说明符为“void”。这样,系统就保证函数不带回任何值。,说 明,对被调函数的声明,7.2.3,一个函数能被另一个函数调用需要以下几个条件: (1)该函数必须已经存在,无论是库函数还是用户自定义函数。 (2)调用库函数时,不需要对函数作声明,只需在源程序的开头用#include命令将相关的头文件包含进来。 (3)调用用户自定义函数时,一般应在主调函数的开始部分对被调函数作声明。,对被调函数

17、的声明,7.2.3,对被调函数的声明有两种形式: (1)一种为传统形式,其一般形式为:类型说明符 函数名( ); (2)另一种为现代形式,其一般形式为:类型说明符 函数名(形参及形参类型说明);,函数定义是指对函数功能的确立,包括指定函数名、函数值的类型、形参及其类型、函数体等。它是一个完整的、独立的函数单位。而函数声明是指对已定义的函数的返回值进行类型说明,它只包括函数名、函数类型等,不包括函数体。其作用是告诉编译系统,在本函数中将要调用的函数是何种类型,以便在主调函数中按此类型对函数值作相应的处理。,说 明,有几种情况可以省略对被调函数的声明: 1.如果被调函数的定义出现在主调函数之前,则

18、可以省略声明。 2.如果在所有函数定义之前,在函数的外部已作了函数声明,则在以后的各主调函数中,可以不必对被调函数作声明。 3.如果函数类型为整型,则在主调函数中可以不要声明。但使用这种方法时,系统无法对参数的类型做检查,因此在调用时若参数使用不当,编译时也不报错。为了程序的安全,建议都加以声明为好。,说 明,函数间的参数传递,7.3,在函数的调用过程中,大部分都存在着数据上的联系,主要表现在两个方面:一是外部数据如何传递到函数内部;二是函数内部加工过的数据如何传递给外部程序。因此 C程序中,函数间的参数传递有两个方面: 1)函数调用时传递给函数的值; 2)函数调用结束时返回给主调函数的值。,

19、值传递,7.3.1,值传递的特点:形参和实参各自占用不同的存储空间,在函数内部对形参的任何操作,其结果只能影响形参的值,而不会影响到实参的值。这种方式只能实现外部数据向函数内部的传递,不能实现函数内部数据向外传递。,【例7-8】,main() int func(int,int); /*函数声明*/int x=2,y=3,z;z=func(x,y); /*函数调用*/printf(“x=%d,y=%d,z=%dn“,x,y,z); int func(int a,int b) /*函数定义*/ int c;a=a+2; b=a+b;c=a+b;return c; ,分析下面程序的运行结果,地址传递

20、,7.3.2,地址传递是将数据的存储地址作为实参传递给形参。按这种方式传递时,形参的类型必须是指针变量或数组名,而实参的类型也只能是变量的地址、数组名(数组的首地址)或指针变量。地址传递的特点:实参和形参指向同一个内存单元地址,即数据在主调函数和被调函数中占用相同的存储单元,因此对形参的操作会影响实参的值。,【例7-9】,/* EX7-9.C */ void fun(int a2) /*函数定义*/ int c;c=a0;a0=a1;a1=c; /*交换a0与a1的值*/ main() int x2=3,8;fun(x); /*函数调用*/printf(“x0=%d,x1=%dn“,x0,x1

21、); ,分析下面程序的运行结果,数组作为函数参数,7.4,数组作为函数的参数有两种形式: (1)一种是把数组元素作为函数的实参,此时形参是普通变量; (2)另一种是把数组名作为函数的实参,此时形参可以是数组名或指针。,数组元素作为函数的实参,7.4.1,数组元素的实质与普通变量相同,因此用数组元素作为函数的实参与普通变量作为函数实参一样,都是把值传递给形参,即单向值传递。,【例7-10】,#include main() int a7=3,2,6,9,10,4,8;int i,x;int tt(int); /*函数声明*/for(i=0;i7;i+) x=tt(ai); /*用数组元素作为函数的

22、实参*/if(x=1) printf(“%dn“,ai); int tt(int y) /*函数定义*/ int z=0;if(y % 2 =1) z=1;return(z); ,分析下面程序的运行结果,/* EX7-10.C */,数组名作为函数实参,7.4.2,用数组名作函数实参时,形参和实参都必须是同类型的数组,而且都有明确的数组说明。当两者的类型不一致时,会发生错误。,1.形参和实参在被调函数和主调函数中都有明确的数组说明,且类型相同。形参在说明时可以指明数组的长度,也可以不指明数组的长度 。 2.前面我们已经介绍,数组名实际上就是数组的首地址。因此用数组名作实参其实质就是将实参数组的

23、首地址传给形参的数组名,这样形参数组就获得实参数组的首地址,使得形参数组和实参数组为同一个数组,共同拥有一段存储空间。当函数结束时,形参数组内容的改变影响实参数组的内容。,注 意,已知某个学生5门课程的成绩,求平均成绩。 float aver(float a ) /*求平均值函数*/ int i;float av,s=0; for(i=0;i5;i+) s += ai;av=s/5;return av; void main() float sco5,av;int i;printf(“ninput 5 scores:n“);for(i=0;i5;i+) scanf(“%f“,注 意,3.形参数组

24、和实参数组在定义时,可以长度不同。因为调用时,只传送数组的首地址而不检查形参数组的长度。因此当实参数组的长度与形参数组的长度不一样时,编译不报错,但程序运行结果有可能不正确,这点请读者注意。 4.多维数组也可以作为函数的参数。在函数定义时可以对形参指定每一维的长度,也可以省略第一维的长度。,函数的嵌套与递归调用,7.5,7.5.1 函数的嵌套调用C语言中函数的定义都是相互平行的、相互独立的,也就是说在函数定义时,函数体内不能包含另一个函数的定义,即函数不能嵌套定义,但可以嵌套调用。,【问题】,#include main() double s,time(); s=time(10); printf

25、(“s=%.2en“,s); double time (int m) double t=1;int sum(); int i;for(i=1;i=m;i+) t=t*sum(i);return t; ,int sum(int n) int s=0,j; for(j=1;j=n;j+) s=s+j; return s; ,1)定义一个sum函数实现12n 2)定义一个time函数实现a1a2am 调用这两个函数,计算: s=1(12) (123) (1210),函数的嵌套调用,图7-23,函数的递归调用,7.5.2,在函数的调用过程中直接或间接地调用自己,这就是函数的递归调用。在递归调用中,主调

26、函数又是被调函数,整个递归过程就是函数不断自我调用的过程,但递归过程不是无限制进行下去,必须有一个结束递归过程的条件。,求 n!=1*2*(n-1)*n 分析: 1 (n=0,1)n!= n*(n-1)! (n1) 程序: #include void main() float fac(int n);int n;float y;printf(“input a number:n“);scanf(“%d“, ,变量的作用域和存储方式,7.6,7.6.1 变量的作用域 变量的作用域是指变量的有效范围,在该范围里,变量是可用的。例如函数的形参变量只能在该函数体内有效,离开该函数就不能再用了。C语言中,变

27、量的说明方式不同,其作用域也不同,通常分为局部变量和全局变量两类。,1.,在一个函数内部定义的变量或复合语句内定义的变量称为局部变量,其作用域仅限于函数内或复合语句内,离开该函数或该复合语句再使用这些变量是非法的。因此在不同的函数内可以定义同名的局部变量,这些同名变量之间不会发生冲突。 编译系统开始并不给局部变量分配内存,只在程序运行过程中,当局部变量所在的函数被调用时,才临时分配内存,调用结束,释放空间。如果变量名相同,则局部变量优先。,局部变量,float f1(int a) int b,c; a,b,c有效 char f2(int x,int y) int i,j,a,b; a,b,x,

28、y,i,j有效 void main( ) int m,n;int c;c=a+b; c有效 m,n有效 ,在所有函数(包括main函数)之外定义的变量称为全局变量,它不属于任何函数,而属于一个源程序文件,其作用域是从定义的位置开始到本源程序文件结束,并且默认初值为0。 在一个源程序中,全局变量和局部变量可以同名,在局部变量有效的范围内,全局变量不起作用。如果要在定义之前使用该全局变量,用extern加以说明,则可扩展全局变量的作用域。,全局变量,2.,int p=1,q=5; /*p,q全局变量*/ float f1(int a) int b,c; char c1,c2; /*c1,c2全局变

29、量*/ char f2(int x,int y) c1,c2 p, q int i,j; 作用范围 作用范围 main() int m,n; ,外部变量与局部变量同名 int a=10,b=5; int min(int a,int b) int c; 形参a,b作用范围c=ab?a:b; 全局变量return (c); 作用范围 main() int a=4; 局部变量范围printf(“%d”,min(a,b); ,外部变量的定义和说明(声明)并不是一回事。 外部变量的定义必须在所有函数之外,且只能定义一次。其一般形式为: extern 类型说明符 变量名1,变量名2,变量名n; 其中: 表

30、示extern可以省略。 外部变量的说明出现在要使用该外部变量且该变量已在函数体内又被定义过的函数内。 外部变量说明的一般形式: extern 类型说明符 变量名1,变量名2,变量名n;,注 意,注 意,外部变量在定义时就分配内存空间,在定义的同时可以赋初值,而外部变量的说明只是表明在该函数内或复合语句内要使用外部变量,不能在说明的同时赋初值。,变量的存储方式,7.6.2,变量的存储方式是指变量使用内存空间的方式,通常可分为“动态存储”和“静态存储”两种。动态存储是指在程序执行过程中,使用到变量时才分配存储单元,使用完毕立即释放。例如函数的形参就属于这种存储方式。静态存储是指在变量定义时就分配

31、存储单元并一直保持,直至整个程序结束。例如全局变量就属于这种存储方式。,静态存储变量是一直存在的,而动态存储变量则时而存在时而消失。这种由于变量存储方式不同而产生的特性称为变量的生存期。生存期表示了变量存在的时间。生存期和作用域是从时间和空间这两个不同的概念来描述变量的特性,两者既有关联,又有区别。一个变量究竟属于哪种存储方式,不能仅从其作用域来判断,还应考虑变量的存储类型。,变量的存储方式,7.6.2,C语言中,变量的存储类型有4种: (1)自动类型auto (2)寄存器类型register (3)静态类型static (4)外部类型extern 不同的存储类型,存放的位置不同: auto类

32、型存储在内存的堆栈区中; register类型存储在CPU的通用寄存器中; static类型存储在内存数据区中; extern类型用于多个编译单位之间数据的传递。,变量的存储方式,7.6.2,1.自动类型 在变量定义的类型前面加上auto,就将变量说明为自动类型。其一般形式为: auto 类型说明符 变量名1, 变量名2, 变量名n; C语言规定:函数内凡未加存储类型说明的变量均视为自动类型存储的变量(简称自动变量) 自动变量属于动态存储方式,即仅当定义自动变量的函数被调用时,系统才分配内存单元,离开该函数,空间释放,自动变量的值消失。,变量的存储方式,7.6.2,通常作为自动变量的有: (1

33、)所有函数的形参变量; (2)凡在复合语句中说明且未加其他说明的变量。 自动变量有以下特点: (1)在函数中定义的只在该函数体里有效,在复合语句中定义的只在该复合语句中有效。 (2)在函数体内定义的自动变量,若没有赋初值,则其初值是随机的。,变量的存储方式,7.6.2,int fat(int a) auto int b,c=3; /*b,c为自动类型变量*/ auto int b,c=3;两者等价 int b,c=3;,2.寄存器类型 在变量定义的类型前面加上register,就将变量说明为寄存器类型。其一般形式为: register 类型说明符 变量名1, 变量名2, , 变量名n; 寄存器

34、类型变量(简称寄存器变量)属于动态存储方式,其生存期和作用域与自动类型变量相同,只不过系统把这类变量直接分配在CPU的通用寄存器中。当需要使用这些变量时,无须访问内存,直接从寄存器中读写,提高了效率。一般寄存器变量只能是int、char或指针型,当CPU无法分配寄存器时,编译系统会自动地将寄存器变量变为自动变量。,变量的存储方式,7.6.2,求阶乘。 int fac(int n) register int i,f=1;for(i=1;i=n;i+)f*=i;return f; main() int i;for(i=1;i=5;i+)printf(“%d!=%dn“,i,fac(i); ,(1)

35、寄存器变量都是局部可用的,只能定义在本函数体内;凡用静态方式存储的变量(如全局变量)不能定义为寄存器变量。 (2)函数中的变量和函数的形参可以定义为寄存器变量。 (3)在使用寄存器变量时,若不对变量赋初值,则其初值是随机的。 (4)寄存器变量没有地址,因此取地址运算符(&)不能用于寄存器变量。 (5)寄存器变量一般用于使用比较频繁的变量,这样可以提高程序的运行速度。,注 意,3.静态类型在变量定义的类型前面加上static,就将变量说明为静态类型。其一般形式为:static 类型说明符 变量名1 , 变量名2, , 变量名n;静态类型变量(简称静态变量)一般分为外部静态变量和内部静态变量两种。

36、,变量的存储方式,7.6.2,(1)外部静态变量 外部静态变量与外部变量相似,是一种公用的全局变量,但作用域不同:外部变量的作用域是整个源程序,而外部静态变量只能在定义它的源文件里有效,在同一源程序的其他源文件里不能使用。 (2)内部静态变量 内部静态变量与自动变量相似,局限于一个特定的函数,退出定义它的函数,即使对于同一文件中的其他函数也是不可用的。但它与自动变量又不同:内部静态变量的值是始终存在的,当函数被调用结束后,内部静态变量保存其值。也就是说,编译系统为内部静态变量分配专用的永久性存储单元。,变量的存储方式,7.6.2,f(int a) auto int b=0;static int

37、 c=3;b+=1;c+=1;return (a+b+c); main() int a=2,i;for(i=0;i3;i+)printf(“%d“,f(a); 结果: 7 8 9,求1*2*3*4*5 int fac(int n) static int f=1;f*=n;return (f); main() int i;for(i=1;i=5;i+)printf(“%d!=%dn“,i,fac(i); ,内部静态变量是局部可用的。 内部静态变量的作用域是在所定义的花括号内有效,其生存期从定义开始直到程序结束,退出花括号,值不丢失,只是不能引用。 若没有给内部静态变量赋初值,则系统自动赋初值0。

38、,注 意,4.外部类型 在变量定义的类型前面加上extern,就将变量说明为外部类型。其一般形式为: extern 类型说明符 变量名1, 变量名2, 变量名n; 外部类型变量(简称外部变量)是定义在所有函数之外的全局变量,在所有函数体内部都是有效的,因此函数间可以通过外部变量直接共享数据。 如果外部变量的定义与使用在同一个文件中,则该文件的函数在使用外部变量时不需进行其他说明,直接可以使用;如果外部变量的定义与使用在两个不同的文件中,则在使用外部变量之前用“extern”存储类型加以说明。,变量的存储方式,7.6.2,声明外部变量扩展它在程序中的作用域。,int max(int x,int

39、y) int z; z=xy?x:y;return (z); main() extern int A,B;printf(“%d“,max(A,B); int A=8,B=19;,内部函数和外部函数,7.6.3,1.内部函数 如果一个函数只能被本文件中其他函数调用,则该函数称为内部函数。在定义内部函数时,只需在函数名和函数类型的前面加static。即: static 类型说明符 函数名(形参表) 内部函数又称静态函数。使用内部函数,可以使函数仅局限于所在的文件,这样在不同文件中同名内部函数之间相互不干扰。通常把只能由同一文件使用的函数和外部变量放入一个文件中,并在它们前面加上static,使之局

40、部化,这样其他文件就不能引用。 如:static int max(int a,int b),2.外部函数 在定义函数时,如果在函数名和函数类型的前面加extern,则表示该函数是外部函数,可供其他函数调用。即:extern 类型说明符 函数名(形参表),内部函数和外部函数,7.6.3,main( ) extern int max(int a,int b);extern float min(float x,float y);extern printf(); file1.c #include int max(int a,int b) file2.c float min(float x,float

41、y) file3.c printf() ,程序举例,7.7,【例7-24】写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数并输出结果。【分析】求最大公约数的方法前面已经介绍过,现编写一个函数gcd来实现该功能。最小公倍数的求法是将两数相乘,然后再被最大公约数相除,得到的值就是最小公倍数,现编写一个函数gcm来实现该功能。主函数main分别调用这两个函数,并进行输出。,【例7-24】,#include “stdio.h“ main() int gcd(),gcm(); int a,b,abd,abm;printf(“intput data a b:n“);scanf(“

42、%d,%d“, ,int gcm(int x,int y,int z) int t; t=x*y/z; return t; ,函数summ的功能是求n个实型数据的和,函数amin是求数组a中最小元素及所在的位置,主函数调用这两个函数,求x44中每行元素的和,并求和中最小数及所在的位置。【分析】summ函数比较容易,只是注意返回值的保存。本程序中,amin函数的编写是关键,求数组中的最小元素,前面我们已经说过,但现在还要求最小数所在的位置,而函数的返回值只有一个,应该怎么做呢?考虑如果最小数的位置是k,那么ak是什么呢?对!就是最小数。所以我们编写这个函数时,让其返回值是最小数的位置而不是最小数

43、。当然也可以通过指针的方法将最小数的位置传出来,这种方法等读者学习过指针后再考虑。main函数给数组x赋值,注意必须用scanf函数将一个实型数赋给普通变量,然后通过这个普通变量将数值赋给数组x。,【例7-25】,#include “stdio.h“ main() int i,j,k; int min(); float sum(); float x44,y4,p,s4;for(i=0;i4;i+)for(j=0;j4;j+) scanf(“%f“, ,float sum(float a,int n) float ss=0; int i; for(i=0;in;i+) ss=ss+ai; ret

44、urn ss; int min(float a,int n) int i,k=0; for(i=0;in;i+) if(aiak) k=i; return k; ,【例7-25】,【例7-26】,#include “stdio.h“ main() long ssq(),t;t=ssq(20);printf(“%ldn“,t); long ssq(int n) long y;if(n=1) y=1;else y=n*n+ssq(n-1);return y; ,用递归的方法编写一函数ssq计算12+22+n2。主函数调用该函数,计算并输出12+22+202,【分析】设 yn= 12+22+n2,由

45、数学知识可得递归计算公式: yn = n2+ yn-1 递归结束条件是:y1=11=1。,/* EX7-26.C */,【例7-27】,下面程序中函数 fun 的功能是:将在字符串s中下标为偶数位置上的字符,紧随其后重复出现一次,放在一个新串t中,t中字符按原字符串中字符的顺序排列。(注意0为偶数)。例如:当s中的字符串为:“ABCDE“时, 则t中的字符串应为:“AACCEE“。 请在注释处修改程序中的错误,使它能得出正确的结果。注意:不要改动main函数,不得增行或删行,也不得更改程序的结构!,【例7-27】,main() char s =“AGDRIPbuk“, t20; fun(s,

46、t); printf(“The result is: %sn“, t); ,fun (char s , char t ) int i, j, sl; sl=strlen(s); i=0;j=0; while(i=sl) /* $ERROR1$ */ t2*j= si; t2*j+1=si; i+; /* $ERROR2$ */ j+; t2*sl= 0; /* $ERROR3$ */ ,【分析】第1个错误是(i=s1),因为C语言中数组下标是从0开始的,s1是字符数组s的长度,而数组s的下标只能从0s1-1,所以正确的是while(isl)。第2个错误是i+,因为题目要求所有的操作都是对下标为

47、偶数的元素,因此下标每次变化是2而不是1,所以正确的是i+=2;。第3个错误是给数组t赋字符串结束标志(0)的位置不对,因为当所有的操作完成后,数组t的下标应该是2*j ,因此应该在2*j的位置上赋字符串结束标志(0),所以正确的是t2*j = 0;。将程序中3处错误改正确后,程序运行结果如图7-39所示。,【例7-27】,#include “stdio.h“ int x=3; main() void cre(); int k; for (k=1;k=x;k+) cre(); void cre() static int x=1; x*=x+1; printf(“ %d“,x); ,【例7-28】,写出下面程序的运行结果,本程序中x既是全局变量,又是内部静态变量,要注意他们各自的生存期和有效范围。main函数中for语句中的x是全局变量x,值等于3。当调用cre函数时,cre函数中的内部静态变量x起作用,由内部静态变量的性质可知:第一次调用结束,x的值为2,第二次调用结束,x的值为6,第三次调用结束,x的值为42,所以程序运行结果为:,

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


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

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

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