计算机技术基础——C程序设计信息科学与工程学院2020年1月11日星期六第八章函数C程序设计第十讲8.9动态存储变量与静态存储变量C程序设计第十讲自动变量的作用域仅限于定义该变量的个体内。在函数中定义的自动变量,只在该函数内有效。自动变量属于动态存储方式,只有在使用它,即定义该变量的函数被调用时才给它分配存储单元,开始它的生存期。函数调用结束,释放存储单元,结束生存期。因此函数调用结束之后,自动变量的值不能保留。由于自动变量的作用域和生存期都局限于定义它的个体内(函数或复合语句内),不同的个体中允许使用同名的变量而不会混淆。自动变量具有以下特点:8.9动态存储变量与静态存储变量C程序设计第十讲•register变量–存放在CPU寄存器中,存取速度快–寄存器变量只能动态分配存储空间(寄存器)–只有自动变量和形参可以作为寄存器变量•举例intfoo(intx){registerinti;/*定义寄存器变量i*/for(i=0;i10000;i++).../*i用于循环变量*/}8.9动态存储变量与静态存储变量C程序设计第十讲外部变量的类型说明符为extern。外部变量和全局变量是对同一类变量两种不同角度的提法。全局变量是从它的作用域提出的,表示了它的作用范围。外部变量从它的存储方式提出的,表示了它的生存期。当一个源程序由若干个源文件组成时,在一个源文件中定义的外部变量在其它的源文件中也有效。外部变量8.9动态存储变量与静态存储变量C程序设计第十讲静态变量的类型说明符是static。静态变量当然是属于静态存储方式,但是属于静态存储方式的量不一定就是静态变量。例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由static加以定义后才能成为静态外部变量,或称静态全局变量。自动变量属于动态存储方式,但也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式。由此看来,变量可由static进行再说明,并改变其原有的存储方式。静态变量8.9动态存储变量与静态存储变量C程序设计第十讲在局部变量说明前加上static说明符就构成静态局部变量。1.静态局部变量例如:staticinta,b;staticfloatarray[5]={1,2,3,4,5};静态局部变量属于静态存储方式,它具有以下特点:(1)静态局部变量在函数内定义,但不象自动变量那样,当调用时就存在,退出函数时就消失。静态局部变量始终存在着,它的生存期为整个源程序。8.9动态存储变量与静态存储变量C程序设计第十讲(2)静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后,尽管该变量还继续存在,但不能使用它。(3)基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。8.9动态存储变量与静态存储变量C程序设计第十讲intf(inta){intb=0;staticintc=3;b++;c++;returna+b+c;}voidmain(){intx=2,i;for(i=0;i3;i++)printf(%d\n,f(x));}i0x2a2b0c3f(x)-1214567898.9动态存储变量与静态存储变量C程序设计第十讲全局变量的说明之前再冠以static就构成了静态全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别:当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。2.静态全局变量8.9动态存储变量与静态存储变量C程序设计第十讲由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static这个说明符在不同的地方所起的作用是不同的。应予以注意。8.10内部函数与外部函数C程序设计第十讲在一个源文件中定义的函数只能被本文件中的函数调用,而不能被同一源程序其它文件中的函数调用,称为内部函数。定义内部函数的一般形式是:static类型说明符函数名(形参表)例如:staticintf(inta,intb)内部函数也称为静态函数。但此处static的含义已不是指存储方式,而是指对函数的调用范围只局限于本文件。因此在不同的源文件中定义同名的静态函数不会引起混淆。内部函数8.10内部函数与外部函数C程序设计第十讲外部函数在整个源程序中都有效。外部函数的定义的一般形式为:extern类型说明符函数名(形参表)例如:externintf(inta,intb)如在函数定义中没有说明extern或static则隐含为extern。在一个源文件的函数中调用其它源文件中定义的外部函数时,应用extern说明被调函数为外部函数。外部函数8.10内部函数与外部函数C程序设计第十讲F1.C(源文件一)main(){externintf1(inti);/*外部函数说明,表示f1函数在其它源文件中*/……}F2.C(源文件二)externintf1(inti);/*外部函数定义*/{……}例如:变量作用域和生存期小结C程序设计第十讲变量存储类型函数内函数外作用域生存期作用域生存期自动变量形式参数寄存器变量静态局部变量静态外部变量†非静态外部变量‡†只限本文件‡其他文件也可以引用课堂练习C程序设计第十讲1、直接或间接调用自身的函数称为______函数。2、存储类别说明符有_____、____、_____和_____。3、在函数之外定义的变量称之为______变量或变量.4、只能被定义它的函数内部所识别的变量为_____。5、要想使函数中的局部变量在函数调用之间保持其值,该变量必须用存储类别说明符______声明.6、被调用函数中的_____语句用来把表达式的值传回给调用函数。答案C程序设计第十讲1、递归2、auto、register、extern、static3、外部、全局变量4、局部变量5、static6、return第九章预处理命令C程序设计第十讲C程序设计第十讲本章要求:掌握无参数宏和带有参数宏定义和使用方法;掌握文件包含的使用方法;掌握条件编译的使用。本章难点:带有参数宏定义和使用方法本章重点:无参数宏和带有参数宏定义和使用方法什么是预处理C程序设计第十讲所谓预处理是指,在对源程序进行编译之前,先对源程序中的预处理命令(主要指宏定义命令、文件包含命令和条件编译命令)进行处理;然后再将处理的结果,和源程序一起进行编译,以得到目标代码。宏定义文件包含条件编译编译预处理编译连接执行#define#include预处理说明C程序设计第十讲在C语言源程序中以“#”号开头的预处理命令都放在函数之外,一般都放在源文件的前面,它们称为预处理部分。所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作。预处理是C语言的一个重要功能,由预处理程序负责完成。对源文件进行编译时,系统将自动引用预处理程序对源程序中预处理部分作处理,处理完再自动进入对源程序的编译。C语言提供了多种预处理功能,主要有宏定义、文件包含、条件编译。预处理说明C程序设计第十讲C语言源程序中用一个标识符来表示一个字符串,称为宏。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。C语言中,“宏”分为有参数和无参数两种。9.1宏定义C程序设计第十讲(一)不带参数的宏定义(二)带参数宏定义无参宏定义C程序设计第十讲一般形式:#define标识符字符串作用是用一个指定的标识符来代表一个字符串。常使用宏定义命令#define定义符号常量,若有如下定义:#definePI3.1415926535即用标识符(称为“宏名”)PI来代表字符串“3.1415926535”。在编译预处理中,即以3.1415926535代替源程序中出现的PI(这个过程称为“宏展开”)。如程序中的s=PI*r*r等效于s=3.1415926535*r*r。无参宏定义C程序设计第十讲说明:(1)标识符(宏名)命名,遵守C语言标识符的命名规则。为便于与一般变量区别,宏名常采用大写字母。(2)宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。如例6-1中有定义:#definePI3.1415926#defineSPI*r*r/*PI是已定义的宏名*/在编译预处理时,语句printf(“TheArea=%lf\n”,S);经宏代换后变为:printf(TheArea=%lf\n,3.1415926*r*r);注意:若替换的字符串中含有其它字符(如上题中的r),一般要在引用宏的程序需要定义,否则编译时会出现标识符(变量)未定义的错误。无参宏定义C程序设计第十讲(3)宏定义是用宏名代表字符串,仅作简单置换,不分配内存空间,编译预处理时不检查语法。只有在源程序被宏展开后,进行编译时才作语法检查。下列的宏定义都不可取:#definePI=3.1415926535/*多了等号*/#definePI3.1415926535;/*多了分号*/上述宏定义对于同一个语句:s=PI*r*r;宏展开后分别为:s==3.1415926535*r*r;s=3.1415926535;*r*r;显然有语法错误!无参宏定义C程序设计第十讲(4)宏替换只对单独的宏名单词进行,对于括在引号中的字符串不起作用。若有宏定义:#defineMAX500对于下列语句:intMAXICOAT=10;/*MAX不是独立单词,不替换*/printf(“MAX=”,MAX);/*前面的MAX在引号中,不替换;后面的要替换*/无参宏定义C程序设计第十讲(5)宏定义必须写在函数之外,宏名的有效范围为定义命令之后到该源文件结束,也可以使用#undef命令来提前终止宏名的作用域。#defineMAX500┇宏名MAX的有效范围#undefMAX┇宏名MAX在此处无效无参宏定义C程序设计第十讲有效地利用宏定义可以简化程序,如对输出格式的宏定义。程序的运行结果为:54.300000584.3000002.710800Youaregood!#definePRprintf#defineNL\n#defineD%d#defineF%f#defineS%svoidmain(){inta=5,b=8;floatx=4.3,y=2.7108;charch[]=Youaregood!;PR(DFNL,a,x);/*printf(%d%f\n,a,x);*/PR(DDFFNL,a,b,x,y);PR(SNL,ch);}有参宏定义C程序设计第十讲C语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。带参宏定义的一般形式为:#define宏名(形参表)字符串带参宏调用的一般形式为:宏名(实参表);宏定义:#defineMAX(x,y)xy?x:y宏调用:z=MAX(3,4);宏展开:z=34?3:4;有参宏定义C程序设计第十讲用定义带参数宏来写程序,输入一个圆的半径,输出圆的面积。定义带参数的宏S(r)。#definePI3.1415926535#defineS(r)PI*r*rvoidmain(){floata,area;a=5;area=S(a);/*宏展开为area=3.1415926535*a*a;*/printf(r=%f\narea=%f\n,a,area);}这样可以解决,无参数宏定义中,