《第13章 预处理和动态存储分配.ppt》由会员分享,可在线阅读,更多相关《第13章 预处理和动态存储分配.ppt(23页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、 第13章 编译预处理和动态 存储分配 高级语言的源程序 编译、连接 目标代码。编译预处理 上机过程:13.1 编译预处理 在C编译程序对源程序进行编译前,由编译预处理程序对预处理命令行(以#号开始的预处理命令行)进行处理,然后对预处理后的源程序进行编译、连接,产生可执行的目标代码。C主要提供三种预处理命令:宏定义、文件包含和条件编译。本章重点介绍前两种。1.宏定义(宏替换)有两种:不带参数宏定义和带参数宏定义。(1)不带参数宏定义形式 define 宏名 替换文本其中:宏名 是用户定义的标识符。替换文本 是字符串。作用:编译预处理程序对源程序中所有表示宏名的标 识符用字符串来替换。例如:#d
2、efine N 100编译预处理程序对源程序中所有N用100替换。例:使用不带参数的宏定义。#define N 10 void main()int aN,i;for(i=0;iN;i+)ai=i*i;for(i=0;iN;i+)printf(“%d“,ai);printf(“n”);说明:1)表示宏名的标识符习惯用大写字母表示,以便与变 量名区别,这并非规定。2)宏定义的位置一般写在程序的开头。3)替换文本中可包含已定义过的宏名。例:#define PI 3.14159#define N 100#define M N*PI最后一个宏定义,编译预处理程序对源程序中所有M用100*3.14159替
3、换。4)宏定义行的最后一个字符是”,表示下一行内容 是本行的续行。例:#define LEAP_YEAR year%4=0&year%100!=0|year%400=0 5)同一个宏名不能重复定义。6)替换文本不能替换双引号中与宏名相同的字符串。例:#define K 2*3.14 void main()printf(“Key”);例:不带参数的宏定义。#define PR printf(“n”)void main()int i,j,k;i=15;j=9;printf(“%d%d”,i+j,i-j);PR;/*展开:printf(“n”)*/printf(“%d%d”,i*j,i/j);PR;
4、/*展开:printf(“n”)*/(2)带参数的宏定义形式#define 宏名(形参表)替换文本其中:宏名 是用户定义的标识符。形参表 指定的形参(由标识符命名),形参之 间用逗号分开。替换文本 是字符串(通常包含指定的形参)。作用:编译预处理程序对源程序中出现的带实参的宏,用实参对#define命令行中的替换文本(字符 串)中形参进行替换。例如:#define F(x,y)x*x+y*y int d1;d1=F(3,2)+10;/*d1=3*3+2*2+10;*/把实参3和2代替宏定义中形参x和y,即F(3,2)表示3*3+2*2。例:带参数的宏定义。#define M(x,y)xy?x:
5、yvoid main()int i,j,k;i=5;j=10;k=10*M(i,j);/*展开:k=10*510?5:10;*/printf(“%dn”,k)说明:1)调用带参数的宏时,实参与形参的个数应相同。2)实参可以是常量、变量或表达式形式。3)带参数宏替换与函数调用有类似之处,但前者对参 数没有类型的要求。4)宏替换中,实参不能替换双引号中的形参。5)与不带参数的宏定义一样,同一个宏名不能重复定 义。(3)终止宏定义形式#undef 已定义宏名例如:#define PI 3.14159 main()#undef PI从终止宏定义(#undef PI)后PI无定义,不代表3.14159了
6、。使用宏定义的优势:1)宏替换不占程序运行时间,只占编译时间。2)便于阅读 3)修改方便注意:宏定义最后没有“;”。2.文件包含 就是在一个文件中,将已有的另外一个文件的全部内容包含进来。由于C的库函数很多,将这些函数根据类型不同分类,分别放在不同的文件中(例如,数学函数:math.h、输入/出:stdio.h、字符函数:ctype.h、字符串:string.h、动态分配:malloc.h 其它:tdlib.h。),编程时,使用哪个文件中的函数,将该文件用文件包含的形式,写在程序的前面。C语言提供了#include 命令行,实现“文件包含”功能,其一般形式为:#include“文件名”或#in
7、clude 编译预程序将用指定的文件中的内容替换此命令行。如果文件名用双引号括起来时,系统先在用户当前目录查找要包含的文件,若找不到,再按标准方式(系统指定的目录)查找;如果文件名用尖括号括起来时,按标准方式查找。说明:1)#include 命令行的位置一般写在源程序的开头,文 件名后缀不一定是“.h”。2)包含文件(头文件)中,可包含一些#define 命令行、外部说明或对库函数的原形说明。例:将格式宏做成头文件format.h。头文件format.h内容如下:#define PR printf#define NL“n”#define D“%dn”#define S“%s”主文件 file1
8、.c 内容如下:#include#include void main()int a=2,b=4;char st=“CHINA”;PR(D,a);/*展开:printf(“%dn”,a)*/PR(D,b);/*展开:printf(“%dn”,b)*/PR(S,st);/*展开:printf(“%s”,st)*/PR(NL);/*展开:printf(“n”)*/3)当包含文件(头文件)修改后,对包含头文件的源程序 必须重进行编译连接。4)在一个程序中允许有多个#include 命令行。5)在包含文件(头文件)中还可以其他文件。例:在包含文件(头文件)file2.h中包含文件file3.h。见下面图
9、示:file1.c file2.h file3.h#include“file2.h”#include“file3.h”不含#include命令行 例:文件包含的程序。#include#include#include void main()float x,y;char s1=”book”,s220;x=1.5;y=sqrt(12*a)+sin(a*3.1416/180);strcpy(s2,s1);printf(“%fn”,y);printf(“%sn”,s2);说明:包含文件也可以是自己编的一些函数,放在一个文件中,使用时只要在程序前部包含进去,文件中的函数可以在程序中调用,节省程序开发时间。
10、3.条件编译 有条件的对源程序的某部分进行编译,减少目标代码的存储空间。有三种形式:形式1:#ifdef 标识符 程序段1#else 程序段2#endif 标识符#define 定义过,则程序段1被编译,否则,程序段2被编译。可选形式2:#ifndf 标识符 程序段1#else 程序段2#endif 标识符没用#define 定义过,则程序段1被编译,否则,程序段2被编译。形式3:#if 表达式 程序段1#else 程序段2#endif 表达式为非0,则程序段1被编译,否则,程序段2被编译。13.2 动态存储分配 在程序执行期间根据需要可动态分配存储空间,不用时可释放。C语言提供的四个标准函数
11、:malloc、calloc、free 和 realloc 可实现前述功能。1.malloc函数和free函数(1)malloc函数调用形式 malloc(size);其中:size 它的类型为unsinged int。功能:分配size个字节存储间。返回指向存储空间首地 址的基类型为void的地址。若分配的存储空间不 足,函数返回空(NULL)。(2)free函数调用形式 free(P);其中:P 类型为指针变量,指向动态分配的地址。功能:将指针P所指的存储空间释放。(无函数返回值)例:函数malloc和free的使用。short int*pi;float*pf;pi=(short*)mal
12、loc(2);/*pi指向short int 2个字节地址*/pf=(float*)malloc(4);/*pf指向float 4个字节地址*/free(Pi);/*释放指针Pi所指的存储空间*/free(Pf);/*释放指针Pf所指的存储空间*/在申请动态存储空间时,若不能确定数据类型所占字节数,可以使用sizeof运算符来求得。例如:short int*pi;float*pf;pi=(int*)malloc(sizeof(int);pf=(float*)malloc(sizeof(float);这是一种常用的形式。2.calloc函数 调用形式:calloc(n,size);其中:n,size 类型均为unsinged int。功能:给n个同一类型长度为size个字节的数据项分配 连续存储空间。若分配成功,返回存储空间的首地址,否则返回空。例:函数calloc的使用。char*ps;ps=(char*)calloc(10,sizeof(char);free(ps);/*释放指针Ps所指的存储空间*/分配10个连续的char类型的存储单元,ps指向存储单元的首地址。