《c语言程序设计教学资料》第7章-函数.ppt

上传人:牧羊曲112 文档编号:5896111 上传时间:2023-08-31 格式:PPT 页数:120 大小:5.13MB
返回 下载 相关 举报
《c语言程序设计教学资料》第7章-函数.ppt_第1页
第1页 / 共120页
《c语言程序设计教学资料》第7章-函数.ppt_第2页
第2页 / 共120页
《c语言程序设计教学资料》第7章-函数.ppt_第3页
第3页 / 共120页
《c语言程序设计教学资料》第7章-函数.ppt_第4页
第4页 / 共120页
《c语言程序设计教学资料》第7章-函数.ppt_第5页
第5页 / 共120页
点击查看更多>>
资源描述

《《c语言程序设计教学资料》第7章-函数.ppt》由会员分享,可在线阅读,更多相关《《c语言程序设计教学资料》第7章-函数.ppt(120页珍藏版)》请在三一办公上搜索。

1、第7章 函数,主要内容,模块化程序设计 函数的定义 向函数传递值和从函数返回值 函数的调用 函数的作用域和存储类别,为什么要用函数?,问题:,如果程序的功能比较多,规模比较大,把所有代码都写在main函数中,就会使主函数变得庞杂、头绪不清,阅读和维护变得困难 有时程序中要多次实现某一功能,就需要多次重复编写实现此功能的程序代码,这使程序冗长,不精炼,在设计一个较大的程序时,往往把它分为若干个程序模块,每一个模块包括一个或多个函数,每个函数实现一个特定的功能 采用“分而治之”的办法简化程序设计的过程 C程序可由一个主函数和若干个其他函数构成 事先编好一批实现各种不同功能的函数 主函数调用其它函数

2、,其它函数也可以互相调用 同一个函数可以被一个或多个函数调用任意多次,用模块化程序设计,main,a,b,c,f,g,h,d,e,i,e,功能分解 自顶而下、逐步求精的过程 模块化分解原则 保证模块的相对独立性 高聚合(模块的功能独立、单一)、低耦合(模块对外接口简单)设计好模块接口 接口是指罗列出一个模块的所有与外部打交道的变量 定义好后不要轻易改动 在模块开头(文件的开头)进行函数声明,模块化程序设计方法,*How do you do!*,例:输出以下的结果,用函数调用实现。,在输出的文字上下分别有一行“*”号,显然不必重复写这段代码,用一个函数printstar来实现输出一行“*”号的功

3、能 再写一个print_message函数来输出中间一行文字信息 用主函数分别调用这两个函数,解题思路:,例:函数调用的简单例子#include void main()void printstar();/*对printstar函数声明*/void print_message();/*对print_message函数声明*/printstar();/*调用printstar函数*/print_message();/*调用print_message函数*/printstar();/*调用printstar函数*/,void printstar()/*定义printstar函数*/printf(*n

4、);void print_message()/*定义print_message函数*/printf(How do you do!n);,运行情况如下:*How do you do!*,(1)一个C程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对较大的程序,一般不希望把所有内容全放在一个文件中,而是将它们分别放在若干个源文件中,由若干个源程序文件组成一个C程序。这样便于分别编写、分别编译,提高调试效率。一个源程序文件可以为多个C程序共用。,说明:,(2)一个源程序文件由一个或多个函数以及其他有关内容(如命令行、数据定义等)组成。一个源程序文件是一个编译单位,在程序编译时是以源程

5、序文件为单位进行编译的,而不是以函数为单位进行编译的。(3)C程序的执行是从main函数开始的,如果在main函数中调用其他函数,在调用后流程返回到main函数,在main函数中结束整个程序的运行。,(4)所有函数都是平行的,即在定义函数时是分别进行的,是互相独立的。一个函数并不从属于另一函数,即函数不能嵌套定义。函数间可以互相调用,但不能调用main函数。main函数是系统调用的。,(5)从用户使用的角度看,函数有两种:标准函数,即库函数。这是由系统提供的,用户不必自己定义这些函数,可以直接使用它们。不同的C系统提供的库函数的数量和功能会有一些不同,但许多基本的函数是共同的。用户自己定义的函

6、数。用以解决用户的专门需要。,(6)从函数的形式看,函数分两类:无参函数。无参函数一般用来执行指定的一组操作。在调用无参函数时,主调函数不向被调用函数传递数据。有参函数。主调函数在调用被调用函数时,通过参数向被调用函数传递数据。,怎样定义函数?,为什么要定义函数定义函数的方法,C语言要求,在程序中用到的所有函数,必须“先定义,后使用”指定函数名字、函数返回值类型、函数实现的功能以及参数的个数与类型,将这些信息通知编译系统。,指定函数的名字,以便以后按名调用 指定函数类型,即函数返回值的类型 指定函数参数的名字和类型,以便在调用函数时向它们传递数据 指定函数的功能。这是最重要的,这是在函数体中解

7、决的,对于库函数,程序设计者只需用#include指令把有关的头文件包含到本文件模块中即可 程序设计者需要在程序中自己定义想用的而库函数并没有提供的函数,函数定义的一般形式,(1)无参函数的定义一般形式(2)有参函数定义的一般形式(3)空函数,函数定义的一般形式,(1)无参函数的定义一般形式,类型函数名()声明部分 语句部分,类型标识符指明函数类型,函数的类型实际上是函数返回值的类型。函数名后面有一个空括号,其中无参数,但是括号不能少。,类型函数名(void)声明部分 语句部分,例如:void hello()printf(“hello world!n”);,(2)有参函数定义的一般形式,类型函

8、数名(类型 形式参数1,类型 形式参数2,)声明部分 语句部分,有参函数比无参函数多了形式参数列表,它们可以是各种类型的变量,个参数之间用逗号间隔。进行函数调用时,主调函数将赋予这些形式参数实际的值,形参是变量,必须在形参表中给出形参的类型说明,例如:int max(int x,int y)int z;/*函数体中的声明部分*/z=xy?x:y;return(z);,(3)空函数,类型函数名(形参列表)例如:,Dummy(形参列表),先用空函数占一个位置,以后逐步扩充 好处:程序结构清楚,可读性好,以后扩充新功能方便,对程序结构影响不大,调用函数,函数的调用形式函数调用时的数据传递函数调用的过

9、程函数的返回值,函数调用的形式,函数调用的一般形式为:函数名(实参表列)如果是调用无参函数,则“实参表列”可以没有,但括号不能省略 如果实参表列包含多个实参,则各参数间用逗号隔开。,按函数调用在程序中出现的形式来分,可以有以下3种函数调用方式:(1)函数调用语句 把函数调用单独作为一个语句 如:printfstar();这时不要求函数带回值,只要求函数完成一定的操作,(2)函数表达式 函数调用出现在另一个表达式中 如:c=2*max(a,b);这时要求函数带回一个确定的值以参加表达式的运算(3)函数参数 函数调用作为另一函数调用时的实参 如:mmax(a,max(b,c);其中max(b,c)

10、是一次函数调用,它的值作为max另一次调用的实参,函数参数:用于函数间数据的传递 形式参数(形参):定义函数时给出的参数 实际参数(实参):调用函数时给出的参数 实参与形参的个数应相等,类型应匹配。实参与形参按顺序对应,一一传递数据。如果实参列表包括多个实参,对实参求值的顺序并不是确定的,有的系统按自左至右顺序求实参的值,有的系统则按自右至左顺序。,说明:,例:实参求值的顺序,如果按自左至右顺序求实参的值,则函数调用相当于f(2,3),如果按自右至左顺序求实参的值,则函数调用相当于f(3,3),函数调用时的数据传递,形式参数:函数名后面括号中的变量名称为“形式参数”(简称“形参”)。实际参数:

11、主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个表达式)称为“实际参数”(简称“实参”)。,实参和形参间的数据传递 在调用函数过程中,系统会把实参的值传递给被调用函数的形参 该值在函数调用期间有效,可以参加被调函数中的运算用return语句返回计算结果,通过函数调用使主调函数得到的确定值。,例:调用函数时的数据传递,运行情况如下:,max is,通过函数调用,可使两个函数中的数据发生联系。,函数调用的过程,在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参被临时分配内存单元。调用结束,形参单元被释放 实参单元仍保留并维持原值,

12、没有改变 如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数的实参的值,关于形参与实参的说明:,(1)在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。只有在发生函数调用时,函数max中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放。(2)实参可以是常量、变量或表达式,例如:max(3,a+b);但要求它们有确定的值。在调用时将实参的值赋给形参。,(3)在被定义的函数中,必须指定形参的类型。(4)实参与形参的类型应相同或赋值兼容。(5)值传递:实参向形参的数据传递是单向“值传递”,只能由实参传给形参,而不能由形参传回来给实参。在调用函数时,给

13、形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。,函数的返回值说明:(1)函数的返回值是通过函数中的return语句获得的。一个函数中可以有一个以上的return语句,执行到哪一个return语句,哪一个语句起作用。return语句后面的括弧也可以不要 例如:“return z;”等价于“return(z);”return后面的值可以是一个表达式。例如:max(int x,int y)return(?:);,(2)函数的返回值应当属于某一个确定的类型,在定义函数时指定函数返回值的类型。例如:下面是3个函数的首行:int max(float x

14、,float y)/*函数值为整型*/char letter(char c1,char c2)/*函数值为字符型*/double min(int x,int y)/*函数值为双精度型*/,注意:凡不加类型说明的函数,自动按整型处理。,(3)在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。,(4)对于不带回值的函数,应当用“void”定义函数为“无类型”(或称“空类型”)。此时在函数体中不得出现return语句。,例:返回值类型与函数类型

15、不同,运行情况如下:1.5,2.5max is 2,1.5,2.6,2.6,2,变为2,main()函数,main()函数是由系统调用的,使得C程序从main()函数开始执行,调用其它函数后流程返回到main()函数,在main()中结束整条程序的运行。若定义main()时没有指定返回值类型,也没有使用void,则返回值默认为int类型,虽然语法允许这样做,但实际编程时通常将main()函数写成如下形式:,第一种形式:用void指明函数没有返回值第二种形式:return返回值的0等价于调用exit()时提供的参数。第三种形式:进一步用void指出main函数没有参数,在一个函数中调用另一函数(

16、即被调用函数)需要具备哪些条件呢?,首先被调用的函数必须是已经存在的函数(是库函数或用户自己定义的函数)。但光有这一条件还不够。如果使用库函数,还应该在本文件开头#include 命令将调用有关库函数时所需用到的信息“包含”到本文件中来。如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面,应该在主调函数中对被调用的函数作声明。,例:对被调用的函数作声明#include void main()float add(float x,float y);/*对被调用函数的声明*/float a,b,c;scanf(f,f,printf(sum is f n,c);float a

17、dd(float x,float y)/*函数定义*/float z;/*函数体*/zxy;return(z);,例:对被调用的函数作声明#include float add(float x,float y)/*函数定义*/float z;/*函数体*/zx+y;return(z);void main()float a,b,c;scanf(“%f,%f,printf(sum is%f n,c);,函数原型的一般形式为:1.函数类型 函数名(类型1,类型2,);2.函数类型 函数名(类型1,参数1,参数2,参数2,);如:float add(float x,float y);float add(

18、float,float);在调用函数时,需要进行函数原型声明,声明的作用:是把函数名、函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。,注意:函数的“定义”和“声明”的区别:函数的定义是指对函数功能的确立,包括指定函数名,函数值类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。函数的声明的作用则是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查。,函数小结,函数的嵌套调用和递归调用,嵌套调用:在定义一个函数时,其函数体内又包含另一个函数的完整定义。递归调用:在调用一个函数

19、的过程中又出现直接或间接地调用该函数本身。,解题思路:main中调用max4函数,找4个数中最大者max4中再调用max2,找两个数中的大者max4中多次调用max2,可找4个数中的大者,然后把它作为函数值返回main函数main函数中输出结果,例:输入4个整数,找出其中最大的数。用函数的嵌套调用来处理。,#include int main()int max4(int a,int b,int c,int d);/*对被调用函数max4的声明*/int a,b,c,d,max;printf(“4 interger numbers:);scanf(%d,%d,%d,%d,int max4(int

20、a,int b,int c,int d)/*max4函数*/int max2(int a,int b);/*对被调用函数max2的声明*/int m;m=max2(a,b);/*a,b中较大者*/m=max2(m,c);/*a,b,c中较大者*/m=max2(m,d);/*a,b,c,d中较大者*/return(m);,int max2(int a,int b)/*max2函数*/if(a=b)return a;else return b;,return(ab?a:b);,int max4(int a,int b,int c,int d)/*max4函数*/int max2(int a,int

21、 b);/*对被调用函数max2的声明*/int m;m=max2(a,b);/*a,b中较大者*/m=max2(m,c);/*a,b,c中较大者*/m=max2(m,d);/*a,b,c,d中较大者*/return(m);int max2(int a,int b)/*max2函数*/return(ab?a:b);,m=max2(max2(a,b),c);,m=max2(max2(max2(a,b),c),d);,return(max2(max2(max2(a,b),c),d);,#include int main()int max4(int a,int b,int c,int d);/*对被

22、调用函数max4的声明*/int a,b,c,d,max;printf(“4 interger numbers:);scanf(%d,%d,%d,%d,int max2(int a,int b)/*max2函数*/return ab?a:b;int max4(int a,int b,int c,int d)/*max4函数*/return max2(max2(max2(a,b),c),d);#include int main()int a,b,c,d,max;printf(4 interger numbers:);scanf(%d,%d,%d,%d,例:函数递归 有5个人坐在一起,问第5个人多

23、少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第3个人,又说比第2个人大2岁。问第2个人,说比第1个人大2岁。最后问第1个人,他说是10岁。请问第5个人多大。,解题思路:要求第5个年龄,就必须先知道第4个年龄 要求第4个年龄必须先知道第3个年龄 第3个年龄又取决于第2个年龄 第2个年龄取决于第1个年龄 每个学生年龄都比其前1个学生的年龄大2,age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10用数学公式表述如下:age(n)=10()age(n-1)+2(),age(5)=age(4)+

24、2,age(4)=age(3)+2,age(3)=age(2)+2,age(2)=age(1)+2,age(1)=10,age(2)=12,age(3)=14,age(4)=16,age(5)=18,回溯阶段,递推阶段,结束递归的条件,可以用一个函数来描述上述递归过程:int age(int n)/求年龄的递归函 int c;/c用作存放函数的返回值的变量 if(n=1)c=10;else c=age(n-1)+2;return c;,运行结果如下:18,用一个主函数调用age函数,求得第5人的年龄。#include int main()printf(%d,age(5);return 0;,例

25、:用递归方法求!,解题思路:,求n!也可以用递归方法,即5!等于4!5,而4!=3!4,!=可用下面的递归公式表示:,!,#include int main()int fac(int n);int n,y;printf(input an integer number:);scanf(%d,int fac(int n)int f;if(n0)printf(n0,data error!);else if(n=0|n=1)f=1;else f=fac(n-1)*n;return(f);,注意溢出,局部变量和全局变量,语句块:程序中被括起来的语句。作用域:每个变量仅在定义它的语句块内有效,并且拥有自己

26、的存储空间 同一个语句块内不可以定义同名变量,不同语句块内可以定义同名变量,在函数内部或复合语句内部定义的变量称为“局部变量”。在一个函数内部定义的变量只在本函数范围内有效 在复合语句内定义的变量只在本复合语句范围内有效,局部变量:,例:float f1(int a)/*函数f1*/int b,c;/*a、b、c有效*/char f2(int x,int y)/*函数f2*/int i,j;/*x、y、i、j有效*/void main()/*主函数*/int m,n;/*m、n有效*/,例:float f1(int a)int b,c;char f2(int x,int y)int i,j;i

27、nt main()int a,b;return 0;,a、b也仅在此函数内有效,类似于不同班同名学生,主函数中定义的变量只在主函数中有效,而不因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其他函数中定义的变量。不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰。形式参数也是局部变量。进入语句块时获得内存,仅能由语句块内语句访问,退出语句块时释放内存,不在有效。,说明:,全局变量,在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量 外部变量是全局变量(也称全程变量)全局变量可以为本文件中其它函数所共用 有效范围为从定义变量的位置开始到本源文件结束从程序运行

28、起即占据内存,程序运行过程中可以随时访问,程序退出时释放内存,int p=1,q=5;/*外部变量*/float f1(int a)/*定义函数f1*/int b,c;char c1,c2;/*外部变量*/char f2(int x,int y)/*定义函数f2*/int i,j;全局变量p,q的作用范围 全局变量c1,c2的作用范围void main()/*主函数*/int m,n;,p、q的有效范围,c1、c2的有效范围,建议:不必要时不要使用全局变量,原因如下:,全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。使用全局变量过多,会降低程序的清晰性。在各个函数执行

29、时都可能改变外部变量的值,程序容易出错。因此,要限制使用全局变量。,降低函数的通用性。因为函数在执行时要依赖于其所在的外部变量。如果将一个函数移到另一个文件中,还要将有关的外部变量及其值一起移过去。但若该外部变量与其他文件的变量同名时,就会出现问题,降低了程序的可靠性和通用性。一般要求把C程序中的函数做成一个封闭体,除了可以通过“实参形参”的渠道与外界发生联系外,没有其他渠道。,例 外部变量与局部变量同名#include int a=3,b=5;/*a,b为外部变量*/void main()int max(int a,int b);int a=8;/*a为局部变量*/printf(%d,max

30、(a,b);/*全局变量b的作用范围*/max(int a,int b)/*a,b为局部变量*/int c;c=ab?ab;形参a、b作用范围 return(c);,运行结果为 8,分析:设置两个函数f、fact。f用于求平方fact用于求阶乘,变量的存储类型,从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量。从变量值存在的时间角度来分,又可以分为静态存储方式和动态存储方式。,静态存储方式:指在程序运行期间由系统分配固定的存储空间的方式。动态存储方式:在程序运行期间根据需要进行动态的分配存储空间的方式。,用户存储空间可以分为三个部分:,将数据存放在此区,全局变量全部存放在静态存储

31、区中,函数形式参数函数中定义的没有用关键字static声明的变量函数调用时的现场保护和返回地址等存放在动态存储区,程序开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中占据固定的存储单元,函数调用开始时分配,函数结束时释放。在程序执行过程中,这种分配和释放是动态的,全局变量全部存储在静态存储区中,在程序开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中占据固定的存储单元。动态存储区中存放以下数据:函数形式参数、自动变量、函数调用时的返回值等。对这些数据,在函数调用开始时分配动态存储空间,函数结束时释放这些空间,在程序执行过程中,这种分配和释放是动态的,如果在

32、一个程序中,两次调用同一函数,分配给此函数中局部变量的存储空间地址可能是不相同的。,变量的基本属性:变量名、变量类型、变量值变量的其它属性:作用域:程序中可引用该变量的区域 存储类别:变量存储在哪里 存储期:变量存活期,变量作用域即可以引用该变量的程序段 C语言中变量可以在三种位置进行定于:函数内部的定于部分函数内部的某一个复合语句内部所有函数之外变量定义的位置决定了变量的作用域 以上三种位置的变量分别对应于:函数作用域 块作用域文件作用域,在一个函数内部定于的变量成为局部变量。在所有函数之外定义的变量成为全局变量。,变量作用域,函数作用域:若变量在函数内所有语句之前定义,则该变量具有函数作用

33、域,只有在定义变量的函数内部才能使用这些变量。块作用域:若变量在复合语句中定义,则其具有块作用域,只在复合语句范围内才能引用该变量。文件作用域。文件作用域:若变量在函数外定义,则该变量具有文件作用域,从变量定义位置开始,到本文件结束为止的区域可以引用该变量。,说明:同一文件中,允许全局变量和局部变量同名,在局部变量的作用域内,外部变量将被屏蔽不起作用。允许函数定义部分定义的变量与该函数内部的复合语句中定义的变量同名。在复合语句执行时,哈数定义部分定义的变量是“隐藏的”,直到复合语句结束。建议:尽量不要这么做,系统不会混淆,但并不意味着人也不会混淆。,例 外部变量与局部变量同名#include

34、int a=3,b=5;/*a,b为外部变量*/void main()int max(int a,int b);int a=8;/*a为局部变量*/printf(%d,max(a,b);/*全局变量b的作用范围*/max(int a,int b)/*a,b为局部变量*/int c;c=ab?ab;形参a、b作用范围 return(c);,运行结果为 8,存储类别包括:自动(auto)静态(static)寄存器(register)外部(extern)变量的存储类别与变量的作用域和生存期等信息存在一定的联系,变量的存储类别,(1)自动变量(auto变量),定义格式:auto 类型名 变量名;(au

35、to可有可无)如果不专门声明存储类别,都是动态地分配存储空间的。函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属此类。在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。因此,这类局部变量称为自动变量。,(2)静态变量(static变量),定义格式:static 类型名 变量名;局部变量和全局变量都可以定义为static存储类别的变量。具有静态存储类别的局部变量称为静态局部变量 具有静态存储类别的全局变量成为静态全局变量,(空字符);,全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的

36、源文件需要用extern 关键字再次声明这个全局变量。静态全局变量与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。,全局变量和静态全局变量:,注意:局部变量改为静态局部变量后,改变了它的生存期,但作用域未变全局变量改为静态全局变量后,改变了它的作用域,但是生存期未变,例:输出1到5的阶乘值#include void main()int fac(int n);int;for(i=1;i=5;i+)printf(%d!=dn,i,

37、fac(i);int fac(int n)static int f=1;f=f*n;return(f);,例:考察静态局部变量的值#include void main()int f(int);int a=2,i;for(i=0;i3;i+)printf(%d”,f(a);int f(int a)auto int b=0;static c=3;b=b+1;c=c+1;return(a+b+c);,调用三次,每调用一次,开辟新a和b,但c不是,第一次调用开始:,3,b,c,第一次调用期间:,b,c,第一次调用结束:,c,0,1,4,4,第二次调用开始:,4,b,c,第二次调用期间:,b,c,第二次

38、调用结束:,c,0,1,5,5,第三次调用开始:,5,b,c,第三次调用期间:,b,c,第三次调用结束:,c,0,1,6,6,f(a)7,f(a)8,f(a)9,()寄存器变量(register变量),定义格式:register 类型名 变量名;一般情况下,变量的值是存放在内存中的。当程序中用到哪一个变量的值时,由控制器发出指令将内存中该变量的值送到运算器中。经过运算器进行运算,如果需要存数,再从运算器将数据送到内存存放。,但是,如果有一些变量使用频繁,则为存取变量的值要花费不少时间。为提高执行效率,C语言允许将局部变量的值放在CPU中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存

39、中去存取。由于对寄存器的存取速度远高于对内存的存取速度,因此这样做可以提高执行效率。这种变量叫做寄存器变量,用关键字register作声明。,例:使用寄存器变量#include void main()long fac(long);long i,n;scanf(%ld,对寄存器变量的说明:只有局部自动变量和形式参数可以作为寄存器变量,其它(全局变量)不行。局部静态变量不能定义为寄存器变量 例如:register static int a,b;错误 一个计算机系统不能定义任意多个寄存器变量,不同系统允许使用的寄存器个数是不同的。,定义格式:extern 类型名 变量名;具有外部存储类型的全局变量又

40、称非静态全局变量,(4)外部变量(extern变量),5.若定义而没有初始化,则自动赋值为0,用extern来声明外部变量,以扩展外部变量的作用域。1.在一个文件内扩展外部变量的作用域 如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”,这样可以从“声明”处起,合法地使用该外部变量。,例:用extern声明外部变量,扩展它在程序文件中的作用域#include void main()int max(int,int);extern int A,B;/*外部变量声明*/printf(“max=%dn,max(A,B);int A=13,B=-8;/

41、*定义外部变量*/int max(int x,int y)/*定义max函数*/int z;z=xy?x:y;return(z);,2.将外部变量的作用域扩展到其他文件 如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量Num,不能分别在两个文件中各自定义一个外部变量Num 应在任一个文件中定义外部变量Num,而在另一文件中用extern对Num作“外部变量声明”在编译和连接时,系统会由此知道Num有“外部链接”,可以从别处找到已定义的外部变量Num,并将在另一文件中定义的外部变量num的作用域扩展到本文件,例:用extern将外部变量的作用域扩展到其他文件。本程序的作用是给定的值,

42、输入和,求a*b和am的值。文件file 1.c中的内容为:#include int A;/*定义外部变量*/void main()int power(int);/*函数声明*/int b=3,c,d,m;printf(“enter the number A and its power m:n);scanf(“d,d,A,);c=A*b;printf(d*d=dn,A,b,c);d=power(m);printf(d*d=dn,A,m,d);,文件file2.c中的内容为:extern int A;/*声明A为一个已定义的外部变量*/int power(int n)int i,y=1;for(

43、i=1;i=n;i+)y*=A;return(y);,存储类别小结,从作用域角度分,有局部变量和全局变量。它们采用的存储类别如下:局部变量包括:自动变量、静态局部变量、寄存器变量。形式参数可以定义为自动变量或寄存器变量。全局变量包括:静态外部变量、外部变量。,(2)从变量存在的时间来区分,有动态存储和静态存储两种类型。静态存储是程序整个运行时间都存在,而动态存储则是在调用函数时临时分配单元。动态存储:自动变量、寄存器变量、形式参数。静态存储:静态态局部变量、静态外部变量、外部变量。,(3)从变量值存放的位置来区分,可分为:内存中静态存储区:静态局部变量、静态外部变量、外部变量。内存中动态存储区

44、:自动变量和形式参数。CPU中的寄存器:寄存器变量。,(4)static对局部变量和全局变量的作用不同。对局部变量来说,它使变量由动态存储方式改变为静态存储方式。而对全局变量来说,它使变量局部化,但仍为静态存储方式。从作用域角度看,凡有static声明的,其作用域都是局限的,或者是局限于本函数内,或者局限于本文件内。,函数的功能要单一,不要涉及多用途的函数 函数的规模要小,尽量控制在50行代码以内 1986年IBM在OS/360的研究结果:大多数有错误的函数都大于500行 1991年对148000行代码的研究结果表明:小于143行的函数比更长的函数更容易维护 参数和返回值的规则 参数要书写完整,不要省略 对函数的入口参数进行有效性检查 没有参数和返回值时,用void填充 每个函数只有一个入口和一个出口,尽量不适用全局变量 尽量少适用静态局部变量,以避免函数具有“记忆”功能,函数设计原则,常见错误,课后习题,

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

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号