
预处理和动态存储.ppt
39页单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,C Programming Language,*,专题之九,编译预处理和动态存储管理,西南石油大学计算机科学学院,主讲:张耀文,考纲分析,编译预处理,1、宏定义:不带参数的宏定义;带参数的宏定义2、文件包含处理分析:这部分主要讨论了预编译,一般会出,1-2,个选择题和,1-2,个填空题这部分好掌握,明确两条:,1,、宏定义,#define,后面的就直接带入,再计算2,、头文件中的,ifndef/define/endif,的作用是,防止该头文件,被重复引用C,语言的预处理程序负责分析和处理以,“#”,为首字符的预处理控制行预处理是在编译前进行的,C,提供的预处理功能主要有以下三种:,1.,宏定义,2.,文件包含,3.,条件编译,分别用宏定义命令、文件包含命令、条件编译命令来实现为了与一般,C,语句相区别,这些命令以符号,“,#”,开头历年真题必学,真题1:下列程序的功能是:给r输入数据后计算半径为r的圆面积s程序在编译时出错2005.9】,main(),int r;float s;,scanf(%d,s=*r*r;,printf(s=%fn,s);,出错的原因是()。
A)注释语句书写位置错误,B)存放圆半径的变量r不应该定义为整型,C)输出语句中格式描述符非法,D)计算因面积的赋值语句中使用了非法变量,真题2:下列4个程序中,完全正确的是()2006.4】,A)#include B)#include,main();main(),/*programming*/*/programming/*/,printf(programming!n);printf(programming!n);,C)#include D)include,main()main(),/*/programming*/*/*programming*/,printf(programming!n);printf(programming!n);,真题3:以下叙述中错误的是()2008.4】,A)在程序中凡是以“#”开始的语句行都是预处理命令行,B)预处理命令行的最后不能以分号表示结束,C)#define MAX是合法的宏定义命令行,D)C程序对预处理命令行的处理是在程序执行的过程中进行的,1 宏定义(,宏替换,),1.1 不带参数的宏定义,简单的字符串替换,一般形式,#define,宏名,字符串,通常,“,宏名,(宏标识符)”,用大写字母表示,用空格分开,,末尾不带“;”,以换行符结束。
define预处理命令不仅可以定义,符号常量,及,字符串,,而且也可以定义,带参数的宏,例,#define,PI,3.1415926,main(),float i,s,r,v;,printf(input raDiuS);,scanf(%f,,i=2.0*,PI,*r;,s=,PI,*r*r;,v=3.0/4*,PI,*r*r*r;,printf(l=%10.4fnS=%10.4fnv=%10.4fn,i,s,v);,(1)宏名一般习惯用,大写字母,表示,以便与变量名相区别但这并非规定,也可用小写字母2)使用宏名代替一个字符串,可以减少程序中重复书写某些字符串的工作量简单不易出错,一改全改使用宏定义,可以提高程序的通用性.,(3)宏定义是用宏名代替一个字符串,也就是作,简单的置换,不作正确性检查4)宏定义不是C语句,,不必在行末加分号5),#define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到本源文件结束通常,#define命令写在文件开头,函数之前,作为文件一部分,在此文件范围内有效6)可以用,#undef命令,终止宏定义的作用域,#define,ge 8.8,main(),|,GE的有效范围,#undef,ge,f1(),由于#undef的作用,使GE的作用范围在#undef行处终止,因此在f1函数中,ge不再代表8.8。
这样可以灵活控制宏定义的作用范围7)在进行宏定义时,可以引用已定义的宏名,可以层层置换例,#define,R,3.0,#define,PI,3.1415926,#define,L,2*,PI*R,#define,S,PI*R*R,main(),printf(L=%fns=%fn,,L,S,);,(8),对程序中,用双括号括起来的字符串内的字符,,即使与宏名相同,也不进行置换9)宏定义是专门用于预处理命令的一个专用名词,它与定义变量的含义不同,,只作字符替换,不分配内存空间,例如:,#define N 10,#define TRUE -1,#define FALSE 0,#define ON 1,#define OFF 0,#define YES 1,#define NO 0,#define PI 3.14159,#define E 2.7183,#define BLACK 0,#define BLUE 1,#define BEGIN ,#define END ,1.2带参数的宏定义,与函数可带形式参数一样,宏标识符也可带有参数在程序中可用实参数替带形式参数,实现宏调用不是进行简单的字符串替换,还要进行参数替换。
其定义的一般形式为,#define宏名(参数表)字符串,字符串中包含在括弧中所指定的参数如:,#defines(a,b)a*b,area=s(3,2);,定义矩形面积S,a和B是边长在程序中用了s(3,2),把3、2分别代替宏定义中的形式,历年真题必学,真题1:下列程序的输出结果是()2005.4】,#define P 3,void F(int x)return(P*x*x);,main(),printf(%dn,F(3+5);,A)192 B)29,C)25 D)编译出错,真题2:下列叙述中正确拘是()2005.4】,A)预处理命令行必须位于源文件的开头,B)在源文件的一行上可以有多条预处理命令,C)宏名必须用大写字母表示,D)宏替换不占用程序的运行时间,真题3:有下列程序:【2005.9】,#define f(x)(x*x),main(),int i1,i2;,i1=f(8)/f(4);i2=f(4+4)/f(2+2);,printf(%d,%dn,i1,i2);,程序运行后的输出结果是()A,),64,28 B,),4,4,C)4,3 D)64,64,真题4:下列,函数rotate的功能是:将a所指N行N列的二维数组中的最后一行放到b所指二维数组的第0列中,把a所指二维数组中的第0行放到b所指二维数组的最后一列中,b所指二维数组中其他数据不变。
2005.9】,#define N 4,void rotate(int a N,int b N),int i,j;,for(i=0;i99,printf(”Compiled for array greater than 99n”);,#else,printf(“”Compiled for small arrayn”);,#endif,运行结果:,Compiled for small array,3.2#ifdef 条件编译,一般形式:,#ifdef 标识符,程序段1,#else,程序段2,#endif,作用是:判断标识符是否被定义过,如果是,则对程序,段1进行编译,否则编译程序段2例如:,#ifdef EGA,#define colar_size 16,#else,#define colar_size 256,#endif,3.3#ifndef 条件编译,一般形式:,#ifndef 标识符,程序段1,#else,程序段2,#endif,作用是,如果标识符未被定义,则编译程序段1,否则编译程序段2例如:,#define USA 1,main(),#ifdef USA,printf(”currency is dollarn”);,#else,printf(”currency is poundn”);,#ifndef FRANCE,printf(”franc cant be usedn”);,#endif,运行结果:,currency is dollar,franc cant be used,编译预处理的几点说明,1,不要混淆预处理行和C语句的概念,。
在本质上预处理行不是C语言本身的组成部分,必须经编译预处理程序处理后,才能进行编译在表现形式上,C语句必须以分号结束,预处理行的末尾不加分号,2 在定义不带参数的宏时,其作用仅仅利用宏名代替一个字符串,系统不做任何语法检查3 在程序定义带参数的宏时,一定要考虑宏展开后的结果,以避免产生与原设计目的不一致的情况历年真题,真题:下列叙述中正确的是()2006.4】,A)预处理命令行必须位于C源程序的起始位置,B)在C语言中,预处理命令行都以#开头,C)每个C程序必须在开头包含预处理命令行:#include,D)C语言的预处理不能实现宏定义和条件编译的功能,二、动态内存分配函数,动态内存分配是指在程序运行过程中,根据需要而分配内存空间的方式在数组应用中,如定义的静态数组太小,则不能满足应用需要,如定义太大,则浪费存储空间,这种情况下,采用动态内存分配的方式可满足这类实际需要多少存储空间就分配多少的应用需要1malloc函数,函数原型:void*malloc(unsigned int size);,功能:在内存动态存储区分配一段长度为size个字节的连续空间,如果分配成功,函数返回一个指向该区域起始地址的指针。
否则如因内存空间不够等原因,则返回空指针(NULL)动态内存分配函数,2calloc函数,函数原型:,void*calloc(unsigned int n,unsigned int size);,功能:,在内存动态存储区分配n个长度为size个字节的连续空间,如果分配成功,函数返回一个指向该区域起始地址的指针,否则返回空指针(NULL)说明,:calloc函数用于为具有n个元素的一维数组动态分配存储空间,每个元素的长度为size个字节,动态内存分配函数,3free函数,函数原型:void free(void*p);,功能:释放指针p指向的存储空间,free函数无返回值说明:p为最近一次调用malloc函数或calloc函数返回的指针4realloc函数,函数原型:void*realloc(void*p,unsigned int size);,功能:将指针p所指向的存储空间,重新分配改变为size个字节,并将原存储空间存放的数据拷贝到新分配的存储空间如果分配成功,函数返回一个指向新存储空间起始地址的指针,否则返回空指针动态内存分配函数,注意:,(1)最好在同一个函数内动态分配和释放存储空间。
2)最好在定义指针时将指针初始化为NULL,在释放指针后也将指针赋值为NULL,这样便于在需判断指针有效性时,用p=NULL判断指针是否为空指针3)ANSI C标准要求动态分配存储空间需将“stdlib.h”文件用#include命令包含在程序中例:一维动态数组,#,include,main,(),int,*p=NULL,n,i,sum;,printf(Please enter array size:);,scanf(%d,p,=(,int*,),malloc,(n*,sizeof,(int);,if,(p=NULL),printf(No enough memory!n);,exit(0);,printf(Please enter the score:);,for,(i=0;in;i+),scanf(%d,p+i);,sum=0;,for,(i=0;in;i+),sum=sum+*(p+i);,printf(aver=%dn,sum/n);,free(p);,例:二维动态数组,#。
