第七章 变量的存储 预处理精选文档.ppt
1 1本讲稿第一页,共三十五页变量的属性变量的属性数据类型数据类型:变量所持有的数据的性质(操作属性)变量所持有的数据的性质(操作属性)存储属性存储属性:存储器类型:存储器类型:寄存器、静态存储区、动态存储区寄存器、静态存储区、动态存储区生存期生存期:变量在某一时刻存在变量在某一时刻存在静态变量与动态静态变量与动态变量变量作用域作用域:变量在某区域内有效变量在某区域内有效局部变量与全局局部变量与全局变量变量变量定义格式:变量定义格式:存储类型存储类型数据类型数据类型变量表变量表;例:例:intsum;externinta,b,c;registerinti;staticfloatx,y;本讲稿第二页,共三十五页变量的作用域变量的作用域w变量的作用域:变量有效的范围。变量的作用域:变量有效的范围。w语言中所有的变量都有自己的作用域。语言中所有的变量都有自己的作用域。w变量说明的方式不同,其作用域也不同。变量说明的方式不同,其作用域也不同。w语言的变量,按作用域范围可分为两种:语言的变量,按作用域范围可分为两种:局部变量和全局变量。局部变量和全局变量。3 3本讲稿第三页,共三十五页局部变量局部变量内部变量内部变量w定义:在函数内定义,只在本函数内有效定义:在函数内定义,只在本函数内有效w说明:说明:mainmain中定义的变量只在中定义的变量只在mainmain中有效中有效不同函数中同名变量,占不同内存单元不同函数中同名变量,占不同内存单元形参属于局部变量形参属于局部变量可定义在复合语句中有效的局部变量可定义在复合语句中有效的局部变量floatf1(inta)intb,c;.charf2(intx,inty)inti,j;main()intm,n;.a,b,c有效有效x,y,i,j有效有效m,n有效有效4 4本讲稿第四页,共三十五页例:不同函数中同名变量例:不同函数中同名变量main()inta,b;a=3;b=4;printf(main:a=%d,b=%dn,a,b);sub();printf(main:a=%d,b=%dn,a,b);sub()inta,b;a=6;b=7;printf(sub:a=%d,b=%dn,a,b);运行结果:运行结果:main:a=3,b=4sub:a=6,b=7main:a=3,b=45 5本讲稿第五页,共三十五页全局变量全局变量外部变量外部变量n定义:在函数外定义,可为本文件所有函数共用。定义:在函数外定义,可为本文件所有函数共用。n有效范围:从定义变量的位置开始到本源文件结有效范围:从定义变量的位置开始到本源文件结束,及有束,及有extern声明的其它源文件。声明的其它源文件。应尽量少使用全局变量,因为:应尽量少使用全局变量,因为:全局变量在程序全部执行过程中占用存储单元全局变量在程序全部执行过程中占用存储单元降低了函数的通用性、可靠性,可移植性降低了函数的通用性、可靠性,可移植性降低程序清晰性,容易出错降低程序清晰性,容易出错定义定义声明声明次数:次数:只能只能1次次可声明多次可声明多次位置:位置:所有函数之外所有函数之外函数内或函数外函数内或函数外分配内存:分配内存:分配内存分配内存,可初始化可初始化不分配内存不分配内存,不可初始化不可初始化外部变量声明:外部变量声明:extern数据类型数据类型变量表;变量表;外部变量定义与外部变量声明不同外部变量定义与外部变量声明不同若外部变量与局部变量同名,则外部变量被屏蔽若外部变量与局部变量同名,则外部变量被屏蔽6 6本讲稿第六页,共三十五页inta=3,b=5;max(inta,intb)intc;c=ab?a:b;return(c);main()inta=8;printf(max=%d,max(a,b);例:外部变量与局部变量例:外部变量与局部变量运行结果:运行结果:max=8例:外部变量定义与声明例:外部变量定义与声明externinta,b;intmax()intz;z=ab?a:b;return(z);main()printf(max=%d,max();inta=13,b=-8;外部变量定义及初始化外部变量声明运行结果:运行结果:max=137 7本讲稿第七页,共三十五页intp=1,q=5;floatf1(inta)intb,c;.intf3().charc1,c2;charf2(intx,inty)inti,j;main()intm,n;.c1,c2的作用范围的作用范围p,q的作用范围的作用范围externcharc1,c2;externcharc1,c2;c1,c2的的作作用用范范围围扩扩展展后后c1,c2的的作作用用范范围围扩扩展展后后8 8本讲稿第八页,共三十五页voidmain()voidgx(),gy();externintx,y;printf(“1:x=%dty=%dn”,x,y);y=246;gx();gy();voidgx()externintx,y;x=135;printf(“2:x=%dty=%dn”,x,y);intx,y;voidgy()printf(“3:x=%dty=%dn”,x,y);例:用例:用extern扩展外部变量作用域扩展外部变量作用域运行结果:运行结果:1:x=0y=02:x=135y=2463:x=135y=2469 9本讲稿第九页,共三十五页引用其它文件中的外部变量引用其它文件中的外部变量intglobal;externfloatx;main()intlocal;.externintglobal;staticintnumber;func2().floatx;unc3()externintglobal;.file1.cfile2.cfile3.c1010本讲稿第十页,共三十五页变量的存储类型变量的存储类型程序区程序区静态存储区静态存储区动态存储区动态存储区全局变量、局部静态变量全局变量、局部静态变量形参变量形参变量局部动态变量(局部动态变量(autoregister)函数调用现场保护和返回地址等函数调用现场保护和返回地址等内存用户区内存用户区11 11本讲稿第十一页,共三十五页n动态变量与静态变量动态变量与静态变量存储方式存储方式w静态存储:静态存储:程序运行期间分配固定存储空间程序运行期间分配固定存储空间w动态存储:动态存储:程序运行期间根据需要动态分配存储空间程序运行期间根据需要动态分配存储空间生存期生存期静态变量:静态变量:从程序开始执行到程序结束从程序开始执行到程序结束动态变量:动态变量:从包含该变量定义的函数开始执行至函数从包含该变量定义的函数开始执行至函数执行结束执行结束变量的存储类型变量的存储类型auto-自动型自动型register-寄存器型寄存器型static-静态型静态型extern-外部型外部型1212本讲稿第十二页,共三十五页n变量存储类型变量存储类型静态静态动态动态存储方式存储方式程序整个运行期间程序整个运行期间函数调用开始至结束函数调用开始至结束生存期生存期编译时赋初值,编译时赋初值,只赋一次只赋一次每次函数调用时每次函数调用时赋初值赋初值自动赋初值自动赋初值0或空字符或空字符不确定不确定未赋初值未赋初值静态存储区静态存储区动态区动态区存储区存储区寄存器寄存器局部变量局部变量外部变量外部变量作用域作用域定义变量的函数或复合语句内定义变量的函数或复合语句内本文件本文件其它文件其它文件局部变量默认为局部变量默认为autoauto型型registerregister型变量个数受限型变量个数受限,且不能为且不能为long,double,floatlong,double,float型型局部局部staticstatic变量具有变量具有全局寿命全局寿命和和局部可见性局部可见性局部局部staticstatic变量具有变量具有可继承性可继承性externextern不用于变量定义不用于变量定义,可扩展外部变量作用域可扩展外部变量作用域register局部局部staticauto外部外部static外部外部存储类别存储类别1313本讲稿第十三页,共三十五页例:文件例:文件file1.cinta;main().f2;.f1;.f1()autointb;f2;.f2()staticintc;C作用域作用域b作用域作用域a作用域作用域mainf2f1mainf1f2maina生存期生存期:b生存期生存期:c生存期生存期:1414本讲稿第十四页,共三十五页main()voidincrement(void);increment();increment();increment();voidincrement(void)intx=0;x+;printf(“%dn”,x);例:局部静态变量值具有可继承性例:局部静态变量值具有可继承性运行结果:运行结果:111main()voidincrement(void);increment();increment();increment();voidincrement(void)staticintx=0;x+;printf(“%dn”,x);运行结果:运行结果:1231515本讲稿第十五页,共三十五页例:变量的寿命与可见性例:变量的寿命与可见性#includeinti=1;main()staticinta;registerintb=-10;intc=0;printf(-MAIN-n);printf(i:%da:%db:%dc:%dn,i,a,b,c);c=c+8;other();printf(-MAIN-n);printf(i:%da:%db:%dc:%dn,i,a,b,c);i=i+10;other();other()staticinta=2;staticintb;intc=10;a=a+2;i=i+32;c=c+5;printf(-OTHER-n);printf(i:%da:%db:%dc:%dn,i,a,b,c);b=a;-Main-i:1a:0b:-10c:0-Other-i:33a:4b:0c:15-Main-i:33a:0b:-10c:8-Other-i:75a:6b:4c:15全局全局i1main:a0b:-10registermain:c0静态静态存储区存储区动态动态存储区存储区other:a2other:b0other:c10843315443other:c106751561616本讲稿第十六页,共三十五页#includeinti=10;intmain()inti=1;printf(%dt,i);inti=2;pritnf(%dt,i);externi;i+=1;printf(%dt,i);printf(%dt,+i);printf(%dn,+i);运行结果为运行结果为:121132 例:例:1717本讲稿第十七页,共三十五页内存动态申请和释放内存动态申请和释放wvoid*malloc(unsignedintsize)在动态存储区分配长度为在动态存储区分配长度为size的连续空间,并返的连续空间,并返回指向该空间起始地址的指针。若分配失败(系回指向该空间起始地址的指针。若分配失败(系统不能提供所需内存),则返回空指针统不能提供所需内存),则返回空指针(NULL)。例:例:int*p=(int*)malloc(sizeof(int)*length);wvoidfree(void*ptr)释放释放ptr指向的内存空间。指向的内存空间。ptr是是malloc()函数返回的函数返回的值。值。例:例:free(p);1818本讲稿第十八页,共三十五页内部函数和外部函数内部函数和外部函数w函数一旦定义后就可被其它函数调用。函数一旦定义后就可被其它函数调用。但当一个源程序但当一个源程序由多个源文件组成时,由多个源文件组成时,在一个源文件中定义的函数能否在一个源文件中定义的函数能否被其它源文件中的函数调用呢被其它源文件中的函数调用呢?w语言把函数分为两类:语言把函数分为两类:n内部函数内部函数n外部函数外部函数1919本讲稿第十九页,共三十五页内部函数内部函数w如果在一个源文件中定义的函数只能被本文件中的函如果在一个源文件中定义的函数只能被本文件中的函数调用,而不能被同一源程序其它文件中的函数调用,数调用,而不能被同一源程序其它文件中的函数调用,这种函数称为内部函数。这种函数称为内部函数。w定义内部函数的一般形式是:定义内部函数的一般形式是:static类型说明符类型说明符函数名函数名(形参表形参表)例如:例如:staticintf(inta,intb)w内部函数也称为静态函数。但此处静态内部函数也称为静态函数。但此处静态static的含义已的含义已不是指存储方式,而是指对函数的调用范围只局限于不是指存储方式,而是指对函数的调用范围只局限于本文件。本文件。2020本讲稿第二十页,共三十五页外部函数外部函数w外部函数在整个源程序中都有效,其定义的一般外部函数在整个源程序中都有效,其定义的一般形式为:形式为:extern类型说明符类型说明符函数名函数名(形参表形参表)例如:例如:externintf(inta,intb)w如在函数定义中没有说明如在函数定义中没有说明extern或或static则隐含为则隐含为extern。在一个源文件的函数中调用其它源文件中定。在一个源文件的函数中调用其它源文件中定义的外部函数时,应义的外部函数时,应用用extern说明被调函数为外部说明被调函数为外部函数。函数。2121本讲稿第二十一页,共三十五页小小结结w可从三个方面对变量分类,即变量的数据类型,变量作可从三个方面对变量分类,即变量的数据类型,变量作用域和变量的存储类型。在第二章中主要介绍变量的数用域和变量的存储类型。在第二章中主要介绍变量的数据类型,本章中介绍了变量的作用域和变量的存储类型。据类型,本章中介绍了变量的作用域和变量的存储类型。w变量的作用域是指变量在程序中的有效范围,变量的作用域是指变量在程序中的有效范围,分为局分为局部变量和全局变量。部变量和全局变量。w变量的存储类型是指变量在内存中的存储方式,分变量的存储类型是指变量在内存中的存储方式,分为静态存储和动态存储,表示了变量的生存期。为静态存储和动态存储,表示了变量的生存期。2222本讲稿第二十二页,共三十五页n作用:对源程序编译之前做一些处理作用:对源程序编译之前做一些处理,有助于有助于提高程序的可移植性、灵活性及编译效率。提高程序的可移植性、灵活性及编译效率。n主要有:主要有:l宏定义宏定义#definel文件包含文件包含#includel条件编译条件编译#if-#else-#endif等等n格式:格式:l“#”开头开头l占单独书写行占单独书写行l语句尾不加分号语句尾不加分号预处理概述预处理概述2323本讲稿第二十三页,共三十五页宏定义宏定义一一、不带参数宏定义、不带参数宏定义n一般形式:一般形式:#define 宏名宏名 宏体宏体n功能:用指定标识符功能:用指定标识符(宏名宏名)代替字符序列代替字符序列(宏体宏体)宏体可缺省,表示宏名定义过或取消宏体如如#define YES 1#define NO 0#define PI 3.1415926#define OUT printf(“Hello,World”);2424本讲稿第二十四页,共三十五页如如 if(x=YES)printf(“correct!n”);else if(x=NO)printf(“error!n”);展开后:展开后:if(x=1)printf(“correct!n”);else if(x=0)printf(“error!n”);宏展开:预编译时,用宏体替换宏名宏展开:预编译时,用宏体替换宏名-不作语法检查不作语法检查定义位置:任意定义位置:任意(一般在函数外面一般在函数外面)作用域:从定义命令到文件结束作用域:从定义命令到文件结束#undef可终止宏名作用域可终止宏名作用域格式:格式:#undef宏名宏名例例#define YES 1 main().#undef YES#define YES 0 max().YES原作用域原作用域YES新作用域新作用域宏定义可嵌套,不能递归宏定义可嵌套,不能递归例例#define MAX MAX+10 ()引号中的内容与宏名相同也不置换引号中的内容与宏名相同也不置换例例#define PI 3.14159 printf(“2*PI=%fn”,PI*2);宏展开:宏展开:printf(“2*PI=%fn”,3.14159*2);宏定义中使用必要的括号宏定义中使用必要的括号()()例例#define WIDTH 80#define LENGTH WIDTH+40 var=LENGTH*2;宏展开:宏展开:var=80+40*2;()()例例#define WIDTH 80#define LENGTH WIDTH+40 var=LENGTH*2;宏展开:宏展开:var=80+40*2;2525本讲稿第二十五页,共三十五页二、带参数宏定义二、带参数宏定义一般形式:一般形式:#define宏名宏名(参数表参数表)宏体宏体例例#define S (r)PI*r*r相当于定义了不带参宏相当于定义了不带参宏S,代表字符串代表字符串“(r)PI*r*r”宏展开:宏展开:形参用实参换,其它字符保留形参用实参换,其它字符保留宏体及各形参外一般应加括号宏体及各形参外一般应加括号()()例例#defineS(a,b)a*b.area=S(3,2);宏展开宏展开:area=3*2;不能加空格例例#define POWER(x)x*x x=4;y=6;z=POWER(x+y);宏展开:宏展开:z=x+y*x+y;一般写成:一般写成:#define POWER(x)(x)*(x)宏展开:宏展开:z=(x+y)*(x+y);2626本讲稿第二十六页,共三十五页#define MAX(x,y)(x)(y)?(x):(y).main()int a,b,c,d,t;.t=MAX(a+b,c+d);宏展开:宏展开:t=(a+b)(c+d)?(a+b):(c+d);int max(int x,int y)return(xy?x:y);main()int a,b,c,d,t;.t=max(a+b,c+d);例:用宏定义和函数实现同样的功能例:用宏定义和函数实现同样的功能2727本讲稿第二十七页,共三十五页带参数宏与函数的区别带参数宏与函数的区别带参数宏带参数宏函数函数处理过程处理过程不分配内存不分配内存简单的字符置换简单的字符置换分配内存分配内存先求实参值先求实参值,再代入形参再代入形参处理时间处理时间编译时编译时程序运行时程序运行时参数类型参数类型无类型问题无类型问题定义实参定义实参,形参类型形参类型程序长度程序长度变长变长不变不变运行速度运行速度不占运行时间不占运行时间调用和返回占时间调用和返回占时间2828本讲稿第二十八页,共三十五页文件包含文件包含n功能:一个源文件可将另一个源文件的内容全部包含进来功能:一个源文件可将另一个源文件的内容全部包含进来n一般形式:一般形式:#include“文件名文件名”或或#include#include“file2.c”file1.cfile2.cfile1.cfile2.cABA处理过程:处理过程:预编译时,用被包含文件的内容取代该预处理命预编译时,用被包含文件的内容取代该预处理命令,再对令,再对“包含包含”后的文件作一个源文件编译。后的文件作一个源文件编译。直接按标准目录搜索“”先在当前目录搜索,再搜索标准目录,文件名可指定路径2929本讲稿第二十九页,共三十五页n被包含文件内容被包含文件内容l源文件源文件(*.c)l头文件头文件(*.h)宏定义数据结构定义函数声明等文件包含可嵌套文件包含可嵌套#include“file2.c”file1.cAfile3.hC#include“file3.h”file2.cBfile1.cAfile3.hfile2.c调用库函数加强类型检查提高程序可读性3030本讲稿第三十页,共三十五页文件包含举例文件包含举例/*powers.h*/#definesqr(x)(x)*(x)#definecube(x)(x)*(x)*(x)#definequad(x)(x)*(x)*(x)*(x)#include#included:myincludepowers.h#defineMAX_POWER10voidmain()intn;printf(numbertexp2texp3texp4n);printf(-t-t-t-n);for(n=1;n=MAX_POWER;n+)printf(%2dt%3dt%4dt%5dn,n,sqr(n),cube(n),quad(n);3131本讲稿第三十一页,共三十五页条件编译条件编译w按不同的条件去编译不同的程序部分,产按不同的条件去编译不同的程序部分,产生不同的目标代码文件。生不同的目标代码文件。w三种形式:三种形式:#ifdef 标识符标识符 程序段程序段1#else 程序段程序段2#endif#ifndef 标识符标识符 程序段程序段1#else 程序段程序段2#endif#if 常量表达式常量表达式 程序段程序段1#else 程序段程序段2#endif3232本讲稿第三十二页,共三十五页条件编译举例条件编译举例#defineDEBUG#ifdefDEBUGprintf(“x=%d,y=%dn”,x,y);#endif3333本讲稿第三十三页,共三十五页小小结结w预处理功能是语言特有的功能,它是在对源预处理功能是语言特有的功能,它是在对源程序正式编译前由预处理程序完成的。程序员程序正式编译前由预处理程序完成的。程序员在程序中用预处理命令来调用这些功能。在程序中用预处理命令来调用这些功能。w宏定义是用一个标识符来表示一个字符串,这宏定义是用一个标识符来表示一个字符串,这个字符串可以是常量、变量或表达式。在宏调个字符串可以是常量、变量或表达式。在宏调用中将用该字符串代换宏名。用中将用该字符串代换宏名。w宏定义可以带有参数,宏调用时是以实参宏定义可以带有参数,宏调用时是以实参代换代换形参,而不是形参,而不是“值传送值传送”。为了避免宏代换时。为了避免宏代换时发生错误,宏定义中的字符串应加括号,字符发生错误,宏定义中的字符串应加括号,字符串中出现的形式参数两边也应加括号。串中出现的形式参数两边也应加括号。本讲稿第三十四页,共三十五页小结(续)小结(续)w文件包含是预处理的一个重要功能,它可用来文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结把多个源文件连接成一个源文件进行编译,结果将生成一个目标文件。果将生成一个目标文件。w条件编译允许只编译源程序中满足条件的程序条件编译允许只编译源程序中满足条件的程序段,使生成的目标程序较短,从而减少了内存段,使生成的目标程序较短,从而减少了内存的开销并提高了程序的效率。的开销并提高了程序的效率。w使用预处理功能便于程序的修改、阅读、移植使用预处理功能便于程序的修改、阅读、移植和调试,也便于实现模块化程序设计。和调试,也便于实现模块化程序设计。3535本讲稿第三十五页,共三十五页