第13章编译预处理和动态存储分配13.1编译预处理13.2动态存储分配2020年1月11日7时25分13.1编译预处理编译预处理:在编译之前进行的处理。C语言的预处理主要有三个方面的内容:1.宏定义;2.文件包含;3.条件编译。预处理命令以符号“#”开头。2020年1月11日7时25分13.1.1宏替换1.不带参数的宏定义:宏定义又称为宏代换、宏替换,简称“宏”。格式:#define标识符替换文本其中的标识符就是所谓的符号常量,也称为“宏名”。预处理(预编译)工作也叫做宏展开:将宏名替换为文本(这个文本可以是字符串、可以是代码等)。掌握宏概念的关键是“换”。即在对相关命令或语句的含义和功能作具体分析之前就要换:例:#definePI3.1415926把程序中全部的标识符PI换成3.14159262020年1月11日7时25分13.1.1宏替换说明:(1)宏名一般用大写(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义(3)可以用#undef命令终止宏定义的作用域(4)宏定义可以嵌套2020年1月11日7时25分13.1.1宏替换2.带参数的宏:除了一般的字符串替换,还要做参数代换格式:#define宏名(参数表)文本例如:#defineS(a,b)a*barea=S(3,2);第一步被换为area=a*b;,第二步被换为area=3*2;2020年1月11日7时25分13.1.1宏替换类似于函数调用,有一个哑实结合的过程:(1)实参如果是表达式容易出问题#defineS(r)r*rarea=S(a+b);第一步换为area=r*r;,第二步被换为area=a+b*a+b;正确的宏定义是#defineS(r)((r)*(r))(2)宏名和参数的括号间不能有空格(3)宏替换只作替换,不做计算,不做表达式求解(4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存(5)宏的哑实结合不存在类型,也没有类型转换。(6)宏展开使源程序变长,函数调用不会(7)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)2020年1月11日7时25分13.1.1宏替换3.终止宏定义可以用#undef提前终止宏定义的作用域例如:#definePI3.14main()……#undefPI2020年1月11日7时25分13.1.2文件包含一个文件包含另一个文件的内容格式:#include“文件名“或#include文件名编译时以包含处理以后的文件为编译单位,被包含的文件是源文件的一部分。编译以后只得到一个目标文件.obj被包含的文件又被称为“标题文件”或“头部文件”、“头文件”,并且常用.h作扩展名。修改头文件后所有包含该文件的文件都要重新编译2020年1月11日7时25分13.1.2文件包含头文件的内容除了函数原型和宏定义外,还可以有结构体定义,全局变量定义:(1)一个#include命令指定一个头文件;(2)文件1包含文件2,文件2用到文件3,则文件3的包含命令#include应放在文件1的头部第一行;(3)包含可以嵌套;(4)文件名称为标准方式,系统到头文件目录查找文件,文件名则先在当前目录查找,而后到头文件目录查找;(5)被包含文件中的静态全局变量不用在包含文件中声明。2020年1月11日7时25分13.2动态存储分配非静态的局部变量是分配在内存中的动态存储区的,这个存储区是一个称为栈的区域C语言还允许建立内存动态分配区域,以存放一些临时用的数据,这些数据需要时随时开辟,不需要时随时释放。这些数据是临时存放在一个特别的自由存储区,称为堆区2020年1月11日7时25分13.2动态存储分配对内存的动态分配是通过系统提供的库函数来实现的,主要有malloc,calloc,free,realloc这4个函数。2020年1月11日7时25分13.2动态存储分配1.malloc函数其函数原型为void*malloc(unsignedintsize);其作用是在内存的动态存储区中分配一个长度为size的连续空间函数的值是所分配区域的第一个字节的地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的开头位置2020年1月11日7时25分13.2动态存储分配malloc(100);开辟100字节的临时分配域,函数值为其第1个字节的地址注意指针的基类型为void,即不指向任何类型的数据,只提供一个地址如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)2020年1月11日7时25分有以下程序段int*p;p=__________malloc(sizeof(int));若要求使p指向一个int型的动态存储单元,在横线处应填入的是()A(int*)BintCint*D(*int)参考答案:A【解析】本题考查malloc函数,题目中要求p指向一个int型的动态存储单元,那么就应该将分配的存储单元转化为int,所以选项A正确。2020年1月11日7时25分13.2动态存储分配2.calloc函数其函数原型为void*calloc(unsignedn,unsignedsize);其作用是在内存的动态存储区中分配n个长度为size的连续空间,这个空间一般比较大,足以保存一个数组。2020年1月11日7时25分13.2动态存储分配用calloc函数可以为一维数组开辟动态存储空间,n为数组元素个数,每个元素长度为size。这就是动态数组。函数返回指向所分配域的起始位置的指针;如果分配不成功,返回NULL。如:p=calloc(50,4);开辟50×4个字节的临时分配域,把起始地址赋给指针变量p2020年1月11日7时25分13.2动态存储分配3.free函数其函数原型为voidfree(void*p);其作用是释放指针变量p所指向的动态空间,使这部分空间能重新被其他变量使用。p应是最近一次调用calloc或malloc函数时得到的函数返回值。2020年1月11日7时25分13.2动态存储分配free(p);释放指针变量p所指向的已分配的动态空间free函数无返回值2020年1月11日7时25分13.2动态存储分配4.realloc函数其函数原型为void*realloc(void*p,unsignedintsize);如果已经通过malloc函数或calloc函数获得了动态空间,想改变其大小,可以用recalloc函数重新分配。2020年1月11日7时25分13.2动态存储分配用realloc函数将p所指向的动态空间的大小改变为size。p的值不变。如果重分配不成功,返回NULL。如realloc(p,50);将p所指向的已分配的动态空间改为50字节2020年1月11日7时25分13.2动态存储分配以上4个函数的声明在stdlib.h头文件中,在用到这些函数时应当用“#includestdlib.h”指令把stdlib.h头文件包含到程序文件中。2020年1月11日7时25分13.2动态存储分配例13.1建立动态数组,输入5个学生的成绩,另外用一个函数检查其中有无低于60分的,输出不合格的成绩。2020年1月11日7时25分13.2动态存储分配解题思路:用malloc函数开辟一个动态自由区域,用来存5个学生的成绩,会得到这个动态域第一个字节的地址,它的基类型是void型。用一个基类型为int的指针变量p来指向动态数组的各元素,并输出它们的值。但必须先把malloc函数返回的void指针转换为整型指针,然后赋给p12020年1月11日7时25分#includestdio.h#includestdlib.hintmain(){voidcheck(int*);int*p1,i;p1=(int*)malloc(5*sizeof(int));for(i=0;i5;i++)scanf(%d,p1+i);check(p1);return0;}2020年1月11日7时25分voidcheck(int*p){inti;printf(Theyarefail:);for(i=0;i5;i++)if(p[i]60)printf(%d,p[i]);printf(\n);}2020年1月11日7时25分