《第9章编译预处理和动态存储分配.doc》由会员分享,可在线阅读,更多相关《第9章编译预处理和动态存储分配.doc(9页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第九章 编译预处理和动态存储分配 考核知识点宏定义、不带参数的宏定义、带参数的宏定义 文件包含 动态存储分配重要考点提示 理解并会使用宏定义 使用常用函数的“文件包含”9.1宏定义1不带参数的宏定义不带参数的宏定义命令行形式如下:#define 宏名 替换文本 或#define 宏名在define宏名和宏替换文本之间要用空格隔开。说明:宏名一般习惯用大写字母表示,宏替换的过程实质上是原样替换的过程。宏定义可以差事少程序中重复办公室某些字符串的工作量。注意:可以用#undef命令终止宏定义的作用域。例如:#define PI 3.14main()PI的作用域#undef PI在进行宏定义时,可以
2、引用已定义的宏名,例如:#define R 15.5#define PI 3.14#define L 2*PI*R2带参数的宏定义定义的一般形式为:#define 宏名(参数表) 字符串宏定义不只进行简单的字符串替换,还要进行参数替换,例如:#define MV(x,y)(x)*(y).a=MV(5,2);/*引用带参的宠名*/b=6MV(a+3,a);以上宏定义命令行中,MV(x,y)称为“宏”,其中MV是一个用户标识符,称为宏名。宏名和左括号“(”必须紧挨着,它们之间不能留有空格,其后圆括号中由称为形参的标识符组成,并且可以有多个形参,各参数之间用逗号隔开,“替换文本”中通常应该包含有形参
3、。执行过程:如果程序中有带实参的宏,则按#define便衣行中指定的字符串从左到右进行了置换。如果字符串中包含宏中的形参(如x,y),则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。如果宏定义中的字符串中的字符不是参数字符(如(x*y)中的“*”号),则保留。这样就形成了置换的字符串。提示:和不带参数的宏定义相同,同一个宏名不能重复定义。在替换带参数的宏名时,圆括号必不可少。带参数的宏和函数之间有一定类似之处,在引用函数时也是在函数右面的括号写实参,也要求实参与形参数目相等,但两者是不同的,主要表现在:函数调用时,要求实参、形参类型相匹配,但在宏替换中,对参数没有类型的要求。函数
4、调用时,先求出实参表达式的值,然后代入形参,而使用带参数的宏只是进行简单的字符串替换。函数调用是在程序运行时处理的,要分配临时的内存单元,还要占用一系列的处理时间。宏替换在编译预处理时完成,因此,宏替换不占运行时间,不被分配内存单元,不进行值的传递,也没有“返回值”的概念。使用宏的次数较多时,宏展开后源程序变长,而函数调用不会。9.2文件包含1文件包含所谓文件包含,是指在一个文件中包含另一个文件的全部内容。C语言用#define命令行来实现文件包含的功能。形式如下:# include “文件名”或# include 在预编译时,预编译程序将用指定文件中的内容来替换此命令行。如果文件名用双引号括
5、起来,则系统先在当前源程序所在的目录内查找指定的包含文件,如果找不到,再按照系统指定的标准方式到有关目录中去寻找。如果文件名用尖括号括起来,系统将直接按照系统指定的标准方式到有关目录中去寻找。说明:# include命令行通常书写在所用文件的最开始部分,所以有时也把包含文件称做“头文件”。头文件名可由用户指定,其后缀不一定用”.h”。当包含文件被修改后,对包含该文件的源程序必须重新进行编译连接,这样才会使修改后的文件生效。在一个包含文件中还可以包含另外的文件。在一个程序中可以有多个#include命令行。9.3条件编译1条件编译在一般情况下,源程序中所有的行都参加编译(注释行除外),但是有时希
6、望其中一部分语句只有在满足某些条件时才进行编译。也就是说要为一部分语句指定编译的条件,如果编译条件成立,就对这部分语句进行编译,这就是“条件编译”。有时,希望当满足某条件时对一组语句进行了编译,而当不满足时则编译另一组语句,条件编译有以下3种形式:#if表达式程序段1#else程序段2#endif它的作用是当指定的表达式值为真(非零)时就编译程序段1,否则编译程序段2。可以事先给定一定条件,使程序在不同的条件下执行不同的功能。#indef 标识符程序段1#else程序段2#endif它的作用是当指定的樯符已经被#define命令定义过,则在程序编译阶段只编译程序段1,否则编译程序段2,其中#e
7、lse部分可以没有。可以参考if语句来理解。#ifdef 标识符程序段1#else程序段2#endif它的作用是若标识符未被定义过,则编译程序段1,否则编译程序段2。9.4关于动态存储的函数我们知道,构成链表结构的每一个节点,是在需要时由系统自动分配存储的,即在需要时才开辟一个节点的存储单元。C语言编译系统是如何动态地开辟和释放存储单元呢?在C语言的库函数中有以下有关函数。1malloc()函数函数原型为:void *malloc(unsigned int size);该函数的作用是系统自动在内存的动态存储区中,分配长度为size的一段连续空间。若此函数执行成功,则函数返回值为指向被分配域的起
8、始地址的指针(该函数的返回值的基本类型为void)。若该函数执行失败(如内存空间不足),则函数返回值为代指针(NULL)。2calloc()函数函数原形为:void *calloc(unsigned n,unsigned size);执行该函数的功能是在内存的动态存储区中分配n个长度为size的连续空间。同样地,若此函数执行成功,则函数返回值为指向被分配域的起始地址的指针(该函数的返回值的基本类型为void)。若该函数执行失败(如内存空间不足的情况),则函数返回空指针(NULL)。3free()函数函数原型为:void free(void *p);该函数的功能是释放由p所指向的那段内存空间,使
9、这段存储空间为他用。p是最近一次调用malloc()或calloc()函数的返回的值。注意:free()函数无返回值。提示:考虑到所编程序要节约内存,同时要保证内存的安全管理,所以对于曾经使用动态存储秋进行分配的指针变量,要在程序结束前,全部用free()函数释放。一选择题1以下叙述中正确的是( )。A用#include包含的头文件的后缀不可以是“.a”B若一些源程序中包含某个头文件,当该头文件有错时,只需要对该头文件进行修改,包含些头文件的所有源程序不必重新进行编译C宏命令行可以看做是一行C语句DC编译中的预处理是在编译之前进行的2下面是对宏定义的描述,不正确的是( )。A宏不存在类型问题,
10、宏名无类型,它的参数也无类型B宏替换不占用运行时间C宏替换时先求出实参表达式的值,然后代入形参运算求值D其实,宏替换只不过是字符替代而已3以下程序的输出结果为( )。#include #define SQR(x)x*xmain()int a,k=3;a=+SQR(k+1);printf(“%dn”,a);A6B10C8D94以下程序的输出结果是( )。#define MIN(x,y)(x)(y):(x):(y)#include main()int i,j,k;i=10;j=15;k=10*MIN(i,j);printf(“%dn”,k);A15B100C10D1505以下程序:#define
11、N 2#define M N+1#define NUM (M+1)*M/2#include main()int i;for(i=1;i=NUM;i+);printf(“%dn”,i);for循环执行的次数是( )。A5B6C8D96以下程序的输出结果是( )。#define FUDGF(y) 2.84+y#define PR(a) printf(“%d”,(int)(a)#define PRINT1(a) PR(a);putchar(n)#include main()int x=2;PRINT1(FUDGF(5)*x);A11B12C13D157以下说法正确的是( )。A#define和pri
12、ntf都是C语句B#define是C语句,而printf不是Cprintf是C语句,但#define不是D#define和printf都不是C语句8以下程序的输出结果是( )。#define f(x) x*x#include main()int a=6,b=2,c;c=f(a)/f(b);printf(“%dn”,c);A9B6C36D189以下程序运行后,输出结果是 ( )。#define PT 5.5#define S(x) PT*x*x#include main()int a=1,b=2;printf(“%4.1fn”,S(a+b);A49.5B9.5C22.0D45.010设有以下宏定
13、义:#define N 3#define Y(n) (N+1)*n)则执行语句:z=2*(N+Y(5+1);后,z的值为( )。A出错B42C48D5411下列程序执行后的输出结果是( )。#define MA(x) x*(x-1)#include main()int a=1,b=2;printf(“%dn”,MA(1+a+b);A6B8C10D1212有如下程序:#define N 2#define M N+1#define NUM 2*M+1main()int i;for(i=1;i=NUM;i+) printf(“%dn”,i);该程序中的for语句循环次数是( )。A5B6C7D813
14、程序中头文件typel.h的内容是:#define N 5#define M1 N*3程序如下:#define “type1.h”#define M2 N*2main()int i;i=M1+M2;printf(“%dn”,i);程序编译后运行的输出结果是( )。A10B20C25D3014以下正确的描述为( )。A每个C语言程序必须在开头使用预处理命令#include B预处理命令必须位于C源程序的首部C在C语言中预处理命令都以“#”开头D在C语言中预处理命令只能实现宏定义和条件编译的功能15从下列选项中选择不会引起二义性的宏定义是( )。A#define POWER(x)x*xB#defi
15、ne POWER(x)(x)*(x)C#define POWER(x)(x*x)D#define POWER(x)(x)*(x)16若有宏定义#define MOD(x,y) x%y,则执行以下语句后的输出为( )。int z,z=15,b=100;z=MOD(b,a);printf(“%dn”,z+);A11B10C6D宏定义不合法17语句typedef long class的作用是( )。A建立了一种新的数据类型B定义了一个整型变量C定义了一个长整型变量D定义了一个新的数据类型标识符18若有以下宏定义:#define N 2#define Y(n)(N+1)*n)则执行语句z=2*(N+Y
16、(5);后的结果是( )。A语句有错误Bx=34Cz=70Dz无定值19对下面程序段,正确的判断是( )。#define A 3#define B(a)(A+1)*a).x=3*(A+B(7);A程序错误,不许嵌套定义Bx=93Cx=21D程序错误,宏定义不许有参数20以下程序的输出结果为( )。#include #define F(y) 3.84+y#define PR(a) printf(“%d”,(int)(a)#define PRINT(a) PR(a);putchar(n)main()int x=2;PRINT(F(3)*x);A8B9C10D11二填空题1下面程序的运行结果为 12
17、 。#define SUB(X,Y)(X)*Y#include main()int a=3,b=4;printf(“%dn”,SUB(a+,b+);2下面程序的运行结果是 a=3,b=7,c=5 。#define JH(x,y) x=xy;y=xy;x=xy#include main()int a=3,b=5,c=7;JH(a,b);JH(b,c);JH(a,c);printf(“a=%d,b=%d,c=%dn”,a,b,c);3设有以下宏定义:#define WITH 80#define LENGTH WIDTH+40则执行赋值语句:v=LENGTH*20;(v为int型变量)后,v的值是
18、880 。4下面程序的运行结果是 212 。#define POWER(x) (x)*x)#include main()int i=1;while(ib?a:b)#include main()int i=6,j=8;printf(“%dn”,MAX(i,j);6下面程序的运行结果是 1,10 。#include #define sw(x,y) x=y;y=xxy;main()int a=10,b=1;sw(a,b);printf(“%d,%dn”,a,b);7下面程序的运行结果是 c=0 。#include main()int a=10,b=20,c;c=a/b;#ifdef DEBUGpri
19、ntf(“a=%d,b=%d”,a,b);#endifprintf(“c=%dn”,c);8若要使指针p指向一个double类型的动态存储单元,请填空。double *p;p= double * malloc(sizeof(double);9以下程序的输出结果是 1.10 。#include void fun(float *p1,float *p2,float *s)s=(float *)calloc(1,sizeof(float);*s=*p1+*p2+;main()float a2=1.1,2.2,b2=10.0,20.0,*s=a;fun(a,b,s);printf(“%5.2fn”,*s);10以下程序的输出结果是 ar=9ar=9ar=11 。#define PR(ar)printf(“ar=%d”,ar)#include main()int j,a=1,3,5,7,9,11,13,15,*p=a+5;for(j=3;j;j-)switch(j)case 1:case 2:PR(*p+);break;case 3:PR(*(-p);