资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,本章重点,13.1,编译预处理,13.2,动态存储分配,第,13,章 编译预处理和动态存储分配,13.1,编译预处理,13.1.1,宏替换,1,无参数的宏定义,宏定义是指用一个指定的标识符(即名字)来代表程序中一个字符串。它的一般形式为:,define,宏名字符串,或,define,宏名,例如,:,define SIZE 10,标识符,SIZE,称为宏名,此命令执行后,预处理程序对源程序中的所有名为,SIZE,的标识符用,10,来替换,此过程就称为“宏替换”。,其中,“”表示这是一条预处理命令,“,define”,为宏定义命令,“宏名”为一个合法的标识符,“字符串”可以是常数、表达式或语句,甚至可以是多条语句。,说明:,(,1,)宏定义与变量定义含义不同,它只作字符替换,并不分配内存空间,也不能认为是赋值。,(,2,)宏定义是用宏名代替一个字符串,是一种机械的置换,不作任何语法检查。,(,3,)宏定义结尾不必加分号。如果加了分号,则被认为是字符串的一部分,即在预处理时,分号也被一起替换。,(,4,)替换文本中也可以包含已定义过的宏名。,(,5,)宏名的有效范围从定义之后到本源文件结束,出了这个文件,宏名便失却了作用,(,6,)若宏名出现在一对双引号中,将不会产生宏替换。例如,如果,ADD,是已经定义的宏名,则不能用与它相关的替换文本来替换,printf(“ADD,”),中的,ADD,。,(,7,)宏定义还可以定义运算符、表达式,甚至可以把输出格式语句作为宏定义。,(,8,)替换文本并不替换用户标识符中的成分。,2,带参数的宏定义,宏定义除了允许定义符号常量外,还可以用于定义带有参数的宏。在宏定义中的参数称为形式参数,简称形参;在宏调用中的参数称为实际参数,简称实参。带参数的宏定义一般形式为:,define,宏名(形参表)字符串,在编译预处理时,程序中凡是带实参的宏,一律按,#define,命令行中指定的字符串从左到右进行替换。 对于字符串中的字符不是参数字符(如*号),则保留不变。,说明,(,1,)宏名与形参表之间不能有空格出现,(,2,)在定义带参数的宏是,一对圆括号必不可少,圆括号中实参的个数应该与形参个数相同,若有多个参数,之间用逗号隔开。,(,3,)宏替换时,实参不能替换扩在双引号中的形参。,(,4,)带参数的宏与带参数的函数的区别:,a.,带参数的宏仅是简单机械的字符替换,并不计算实参表达式的值;,b.,宏名无类型,宏参数也不存在类型问题,因此宏定义中的字符串可以是任何类型的数据,而函数中的实参和形参都要定义类型,两者要求一致;,c.,宏替换是预编译处理时进行的,不占运行时间,而函数调用则是在程序运行时进行的,占用运行时间(如分配单元、保留现场、值传递、返回等);,d.,宏是原样替换,展开后源程序增长,而函数调用则不会。,以下程序运行结果是(),#include ,#define N 5,#define M N+1,#define,f(x,) (x*M),main(), int i1, i2;,i1=f(2);,i2=f(1+1);,printf(”%d %dn”, i1,i2);,11 7,13.1.2,文件包含,在用,C,语言开发程序时,我们可以把一些宏定义按照功能分别存入不同的文件中,当我们需要使用某类宏定义时,就无需在程序中重新去定义,而只要把这些宏定义所在的文件包含在程序的开头就可以了。,文件包含是指一个源程序文件将另一个指定文件的全部内容包含进来,即将另一个文件包含到本文件之中。这一过程通过预处理命令,#include,来完成。文件包含预处理语句的一般形式为:,include,或,include,“包含文件”,其中,包含文件名是磁盘中文本文件的名字。例如:,#include ,或,#include ,stdio.h,在编译时,预编译程序将用指定文件中的内容来替换此命令行。,13.2,动态存储分配,此前,我们用于存储数据的变量和数组都必须在说明部分进行定义。,C,编译程序通过定义语句了解它们所需存储空间的大小,并预先为其分配适当的内存空间。这些空间一经分配,在变量或数组的生存期内是固定不变的。所以这种方式也称为“静态存储分配”。,C,语言中还有一种“动态存储分配”的内存空间分配方式,在程序执行期间需要空间来存储数据时,通过申请分配指定的内存空间;当有闲置不用的空间时,可以随时将其释放,由系统另作它用。用户可以通过调用,C,语言提供的标准库函数来实现动态分配,从而得到指定数目的内存空间或释放指定的内存空间。,13.2.1,malloc,函数和,free,函数,1,malloc,函数,malloc,函数的调用形式为:,malloc,(,size,),其中,size,的类型为,unsigned,int,,函数返回值类型为,void*,。,2,free,函数,free,函数调用的形式为:,free(p,),p,是指针变量,必须指向由动态分配函数,malloc,分配的地址,,free,函数将指针,p,所指的存储空间释放,使这部分空间可以由系统重新支配。此函数没有返回值。,13.2.2,calloc,函数,calloc,函数的调用形式为:,calloc(n,size,);,n,和,size,的类型都为,unsigned,int,型。其返回值的类型为,void*,。,calloc,函数用来给,n,个同一类型的数据项分配连续的存储空间。每个数据项的长度为,size,个字节,若分配成功,函数返回存储空间的首地址。否则返回空。由调用,calloc,函数所分配的存储单元,系统自动设置初值为,0,。,例如:,char *,ps,;,ps,=(char *)calloc(10,sizeof(char);,以上语句开辟了,10,个连续的,char,类型的存储单元,由,ps,指向存储单元的首地址。每个存储单元可以存放一个字符。,显然,使用,calloc,函数开辟的动态存储单元相当于开辟了一个一维数组。函数的第一个参数决定了一维数组的大小;第二个参数决定了数组元素的类型。函数的返回值就是数组的首地址。,使用,calloc,函数开辟的动态存储单元,同样用,free,函数释放。调用形式:,free(p,),1.,以下程序运行后的输出结果是(),#include ,#define PT 3.5;,#define,S(x,) PT*X*X,;,main(),int,a=1, b=2;,printf(“%4.1fn”,S(a+b);,A) 14.0 B) 31.5 C) 7.5 D),程序出错,2.,设有宏定义:,#define,IsDIV(k,n,) (,k%n,=1)?1:0),且变量,m,已正确定义并赋值,则宏调用,IsDIV(m,5)& IsDIV(m,7),为真时,所要表达的是(),A,)判断,m,是否能被,5,或者,7,整除,B),判断,m,是否能被,5,和,7,整除,C),判断,m,被,5,或者,7,整除是否余,1,D),判断,m,被,5,和,7,整除是否余,1,以下程序运行的结果是(),#include ,#include ,int fun( int n), int *p;,p=(,int,*),malloc(sizeof(int,);,*p=n; return *p;,main(), int a;,a=fun(10); printf(“%dn”, a+fun(10);,A) 0 B) 10 C) 20 D),出错,4.,以下关于宏定义的叙述中,正确的是(),A),宏名必须用大写字母表示,B),宏定义必须位于源程序中所有语句之前,C),宏替换没有数据类型限制,D),宏调用比函数调用耗费时间,5.,以下叙述中错误的是(),A),在程序开中凡是以“,#”,开始的语句都是预处理命令行,B),预处理命令行的最后不能以分号表示结束,C) #define MAX,是合法的宏定义命令行,D) C,程序对预处理命令行的处理是在程序执行的过程中进行的,有一个名为,init.txt,的文件,内容如下:,#define HDY(A,B) A/B,#define PRINT(Y) printf(“y=%dn”, Y),以下程序的运行结果是(),#include “,intit.txt,”,main(),int,a=1, b=2, c=3,d=4, k;,k=,HDY(a+c,b+d,);,PRINT(k,);,A),编译有错,B),运行出错,c) y=0 D) y=6,8.,以下叙述中错误的是(),A) C,程序中的,#include,和,#define,行均不是,C,语句,B),除逗号运算符外,赋值运算符的优先级最低,C) C,程序中,,j+,是赋值语句,D) C,程序中,,+,、,-,、*、,/,和,%,是算术运算法,可用于整型和实型数的运算,9,)若有宏定义:,#define N 100,,则以下叙述中正确的是(),A,)宏定义中定义了标识符,N,的值为整数,100,B),在编译程序对,C,源程序进行预处理时,用,100,替换标识符,N,C),对,C,源程序进行编译时,用,100,替换标识符,N,D),在运行时,用,100,替换标识符,N,
展开阅读全文