C二级 第9章 编译预处理和动态存储分配
二级C语言-编译预处理和动态存储分配、结构体和共用体、文件(一)
二级C语言-编译预处理和动态存储分配、结构体和共用体、文件(一)(总分:100.00,做题时间:90分钟)一、{{B}}选择题{{/B}}(总题数:40,分数:100.00)1.以下函数的功能是,通过键盘输入数据,为数组中的所有元素赋值。
在下划线处应填入的是______。
#define N 10void arrin(int x[N]){ int i=0; while(i<N)scanf("% d", ______);}∙ A.x+i∙ B.&x[i+1]∙ C.x+(i++)∙ D.&x[++i](分数:2.50)A.B.C. √D.解析:[解析] 本题考查了宏替换的知识,同时考查了自加的知识,因为要通过键盘输入数据,为数组中的所有元素赋值,所以下标要从0开始到9,只有选项C可以满足。
2.下面是对宏定义的描述,不正确的是______。
∙ A.宏不存在类型问题,宏名无类型,它的参数也无类型∙ B.宏替换不占用运行时间∙ C.宏替换时先求出实参表达式的值,然后代入形参运算求值∙ D.其实,宏替换只不过是字符替代而已(分数:2.50)A.B.C. √D.解析:[解析] 本例涉及宏替换的基本概念及与函数的简单比较,题目中的选项也确实是需要了解的一般知识。
在本例中,宏替换的实质恰如选项D所言,是字符替代,因此,不会有什么类型,当然,就更不可能进行计算(C错误)。
带参数的宏与函数相比,宏在程序编译之前已经将代码替换到程序内,执行时不会产生类似于函数调用的问题,可以说不占运行时间。
3.有以下程序:#define N 2#define M N + 1#define NUM (M+1)*M/2#include <stdio.h>main(){ int i;for(i=1; i<=NUM; i++);printf("% d/n", i);}for循环执行的次数是______。
编译预处理和动态存储分配
2 .带参数的宏定义
2)和不带参数的宏定义相同,同一个宏名不能重复定义,除非两个宏定义命令行完 全一致。 3)在调用带参数的宏名时,一对圆括号必不可少,圆括号中实参的个数应该与形参 个数相同。 • 在预编译时,编译预处理程序用“替换文本”来替换宏,并用对应的实参来替换“替 换文本”。 4)在“替换文本”中的形参和整个表达式应该用括号括起来。 5)宏替换中,实参不能替换括在双引号中的形参。
1 .malloc函数 函数的调用形式: malloc( size) 其中,malloc函数返回值的类型为void *;size的类型为unsigned int。 功能:分配size个字节的存储区,返回一个指向存储区首地址的基类型为 void的地址。若没有足够的内存单元供分配,函数返回空( NULL)。
3 . calloc函数 函数的调用形式为: calloc ( n, size); 其中:n和size的类型都为unsigned int,calloc函数返回值的类型为void *。 功能:给n个同一类型的数据项分配连续的存储空间,每个数据项的长度为 size个字节。若分配成功,函数返回存储空间的首地址;否则返回空。通过调用 该函数所分配的存储单元,系统自动置初值0。
1.不带参数的宏定义:
不带参数的宏定义命令行形式: • #define 宏名 替换文本
注意
在define、宏名和宏替换文本 之间要用空格隔开。宏名不得 与程序中的其他名字相同。
例如
#define SIZE 100 编译时,在此命令行之后,预处理程序对源 程序中的所有名为SIZE的标识符用100来 替换,这个替换过程称为“宏替换”。
1.不带参数的宏定义:
2)替换文本中可以包含已定义过的宏名。
例如
编译原理第九章 运行时存储空间组织
– 堆区(new, malloc)
9.5 嵌套过程语言的栈式实现
• Pascal 的过程嵌套 嵌套层次:主程序0层 ······ 采用层数计数器,每逢Proc Begin加1,遇 Proc End则减1。
• 直接外层 • 编译器需要将过程的层数记录到符号表中
2)返回函数结果:累加器、寄存器
··· a:= 3 ··· P(a); Write(a); ···
传地址 8,8 8
举例
Procedure P(x) Begin
x:=x+5; writeln(x,a); End;
传结果 8,3 8
传值 8,3 3
举例
begin
Procedure P(x,y,z) …P(a+b,a,a)
初等类型数据采用确定“字长”,数组按列存放,边界对齐。
这样,可将过程活动单元(局部数据区)直接安排在 过程目标码之后,以便运行时访问。
9.3 Fortran静态存储分配(2)
数据区
返回地址 调用程序返回地址(调用恢复地址)
寄存器保护区 保存调用程序的寄存器运行环境
形式单元 形参
简单变量 数组 临时变量
P ->S ->Q =》R ->R
Program P; var a,x…
Top
R
procedure Q(b)
SP
var i…
R
procedure R(u,v)
动
var c,d…
态
begin… R… end {R} 链
Q
begin … R… end{Q} procedure S
预处理和动态存储分配
(1)有以下程序main(){ char p[]={'a', 'b', 'c'}, q[]="abc";printf("%d %d\n", sizeof(p),sizeof(q)); };程序运行后的输出结果是A)4 4 B)3 3 C)3 4 D)4 3(2)有以下程序# define f(x) (x*x)main(){ int i1, i2;i1=f(8)/f(4) ; i2=f(4+4)/f(2+2) ;printf("%d, %d\n",i1,i2);}程序运行后的输出结果是A)64, 28 B)4, 4 C)4, 3 D)64, 64(3)有以下程序main(){ char a[7]="a0\0a0\0";int i,j;i=sizeof(a); j=strlen(a);printf("%d %d\n",i,j);}程序运行后的输出结果是A)2 2B)7 6D)6 2(4)以下叙述中正确的是A)预处理命令行必须位于源文件的开头B)在源文件的一行上可以有多条预处理命令 C)宏名必须用大写字母表示D)宏替换不占用程序的运行时间(5) 有以下程序main( ){ char a[]=”abcdefg”,b[10]=”abcdefg”;printf(“%d%d\n”,sizeof(A) ,sizeof(B) );}执行后输出结果是A) 7 7 B) 8 8 C) 8 10 D) 10 10(6) 有以下程序#define f(x) x*xmain( ){ int i;i=f(4+4)/f(2+2);printf(“%d\n”,i);}执行后输出结果是A) 28 B) 22 C) 16 D) 4(7) 有以下程序#include <stdio.h>#define F(X,Y) (X)*(Y)main (){ int a=3, b=4;printf("%d\n", F(a++,b++));}程序运行后的输出结果是A) 12 B) 15 C) 16 D) 20(8) 有以下程序main(){ char s[]="\n123\\";printf("%d,%d\n",strlen(s),sizeof(s));}执行后输出结果是A) 赋初值的字符串有错 B) 6,7 C) 5,6 D) 6,6(9) 有以下程序main(int arge,char *argv[]){ int n,i=0;while(arv[1][i]!='\0'{ n=fun(); i++;}printf(%d\n",n*argc);}int fun(){ static int s=0;s+=1;return s;}假设程序经编译、连接后生成可执行文件exam.exe,若键入以下命令行 exam 123<回车>则运行结果为(10) 有以下程序main(){ char a[ ]={…a‟,…b‟,…c‟,…d‟, …e‟, …f‟, …g‟,…h‟,…\0‟}; int i,j;i=sizeof(a); j=strlen(a);printf(“%d,%d\b”i,j);}程序运行后的输出结果是A)9,9 B)8,9 C)1,8 D)9,8(11) 程序中头文件typel.h 的内容是:#define N 5#define M1 N*3程序如下:#define “type1.h”#define M2 N*2main(){ int i;i=M1+M2; printf(“%d\n”,i);}程序编译后运行的输出结果是:A) 10 B) 20 C) 25 D) 30(12) 有以下程序#include <stdlib.h>main(){ char *p,*q;p=(char*)malloc(sizeof(char)*20); q=p;scanf(“%s%s”,p,q);printf(“%s%s\n”,p,q);}若从键盘输入:abc def<回车>,则输出结果是:A) def def B) abc def C) abc d D) d d(13) 若指针p已正确定义,要使p指向两个连续的整型动态存储单元,不正确的语句是A) p=2*(int*)malloc(sizeof(int));B) p=(int*)malloc(2*sizeof(int));C) p=(int*)malloc(2*2);D) p=(int*)calloc(2,sizeof(int));(14) 以下程序的输出结果是main(){ char st[20]= “hello\0\t\\\”;printf(%d %d \n”,st rlen(st),sizeof(st));}A) 9 9 B) 5 20 C) 13 20 D) 20 20(15) 以下程序的输出结果是amovep(int p, int (a)[3],int n){ int i, j;for( i=0;i<;i++)for(j=0;j<n;j++){ *p=a[i][j];p++; }}main(){ int *p,a[3][3]={{1,3,5},{2,4,6}};p=(int *)malloc(100);amovep(p,a,3);printf(“%d %d \n”,p[2],p[5]);free(p);}A) 56 B) 25 C) 34 D) 程序错误(16) 以下程序的输出结果是#define M(x,y,z) x*y+zmain(){ int a=1,b=2, c=3;printf(“%d\n”, M(a+b,b+c, c+a));}A) 19 B) 17 C) 15 D) 12(17) 以下程序的输出结果是A) 16 B) 2 C) 9 D) 1#define SQR(X) X*Xmain(){ int a=16, k=2, m=1;a/=SQR(k+m)/SQR(k+m);printf(“d\n”,a);}(18) 若定义了以下函数:void f(……){……*p=(double *)malloc( 10*sizeof( double));……}p是该函数的形参,要求通过p把动态分配存储单元的地址传回主调函数,则形参p的正确定义应当是A) double *p B) float **p C) double **p D) float *p(19) 有如下程序#define N 2#define M N+1#define NUM 2*M+1#main(){ int i;for(i=1;i<=NUM;i++)printf(“%d\n”,i);}该程序中的for循环执行的次数是A) 5 B) 6 C) 7 D) 8(20) 下列程序执行后的输出结果是A) 6 B) 8 C) 10 D) 12#define MA(x) x*(x-1)main(){ int a=1,b=2; printf("%d \n",MA(1+a+b));}(21) 若有说明:long *p,a;则不能通过scanf语句正确给输入项读入数据的程序段是A) *p=&a;scanf("%ld",p);B) p=(long *)malloc(8);scanf("%ld",p);C) scanf("%ld",p=&a);D) scanf("%ld",&a);(22) 以下程序的输出结果是A) 1 B) 4 C) 7 D) 5#includeint a[3][3]={1,2,3,4,5,6,7,8,9,},*p;main( ){ p=(int*)malloc(sizeof(int));f(p,a);printf("%d \n",*p);}f(int *s,int p[][3]){ *s=p[1][1];}(23) 以下程序的输出结果是A) 9 B) 6 C) 36 D) 18#define f(x) x*xmain( ){ int a=6,b=2,c;c=f(a) / f(b);printf("%d \n",c);}(24) 以下程序运行后,输出结果是A) 49.5 B) 9.5 C) 22.0 D) 45.0#include<stdio,h>#define PT 5.5#define S(x) PT* x * xmain(){ int a=1,b=2;printf("%4.1f\n",S(a+b));}(25) 以下程序运行后,输出结果是A) 1 B) 7 C) 9 D) 11fut(int **s, int p[2][3]){ **s=p[1][1];}main(){ int a[2][3]={1,3,5,7,9,11}, *p;p=(int *) malloc(sizeof(int));fut(&p,a);printf("%d\n",*P);}(26) 设有以下宏定义:#define N 3#define Y(n) ( (N+1)*n)则执行语句:z=2 * (N+Y(5+1));后,z的值为A) 出错 B) 42 C) 48 D) 54(27) 若有说明,double *p,a;则能通过scanf语句正确给输入项读入数据的程序段是 A)*p=&a; scanf("%lf",p); B)p=(double *)malloc(8);scanf("%f",p);C) p=&a;scanf("%lf",a); D)p=&a; scanf("%le",p);(28) 执行下面的程序后,a的值是#define SQR(X) X*Xmain( ){ int a=10,k=2,m=1;a/=SQR(k+m)/SQR(k+m);printf("%d\n",a); }A) 10 B) 1 C) 9 D) 0(29) 以下程序的输出结果是fut (int**s,int p[2][3]){ **s=p[1][1]; }main( ){ int a[2][3]={1,3,5,7,9,11},*p;p=(int*)malloc(sizeof(int));fut(&p,a);primtf("%d\n",*p); }A) 1 B) 7 C) 9 D) 11(30) 若要用下面的程序片段使指针变量p指向一个存储整型变量的动态存储单元: int *p;p=__________ malloc( sizeof(int));则应填入A) int B) inst * C) (*int) D) (int *)(31) 请读程序:#include<stdio.h>#define SUB(X,Y) (X)*Ymain(){ int a=3, b=4;printf("%d", SUB(a++, b++));}上面程序的输出结果是A) 12 B) 15 C) 16 D) 20(32) 请读程序:#include<stdio.h>void fun(float *pl, float *p2, float *s){ s=( float * )calloc( 1, sizeof(float));*s=*p1+ *(p2++);}main(){ float a[2]={1.1, 2.2}, b[2]={10.0, 20.0}, *s=a;fun(a, b, s)printf("%f\n",*s);}上面程序的输出结果是A) 11.100000 B) 12.100000 C) 21.100000 D) 1.100000(33) 在宏定义#define PI 3.14159中,用宏名PI代替一个A) 单精度数 B) 双精度数 C) 常量 D) 字符串(34) 请选出以下程序段的输出结果#include<stdio.h>#define MIN(x,y) (x)<(y)? (x):(y)main(){ int i,j,k;i=10; j=15;k=10*MIN(i,j);printf("%d\n",k);}A) 15 B) 100 C) 10 D) 150(35) sizeof(double)是【35】。
第十节-编译预处理和动态存储分配
函数的返回值为该区域的首地址。
注意事项:
①这里n和size表示大于0的整数值
②calloc函数返回该区域的地址(首地址)。
③calloc默认返回的地址类型为void*, 可以保存
任意类型数据的地址。
赋予指针变量p
int *p = (int*)malloc(4)
*p=100;
分配一个double类型大小的存储空间, 并将该存储空间的地址
赋予指针变量p
double *p = (double*)malloc(8)
*p=3.14;
()分配内存空间函数 calloc
定义:calloc(n, size)
程序的入口
(1)无参形式的主函数
main()
{
函数体
}
(2)带参形式的主函数
main(int argc, char* argv[10])
{
பைடு நூலகம் 函数体
}
注意事项:
①argc表示输入参数的数量(包括程序文件名)
②argv保存输入参数的内容(包括程序文件名)
【例】程序文件名为ttt.exe, 当执行程序之后:
输出结果:100
#define A(a) a+a
#define B(b) A(b) * b
printf("%d\n", B(10))
输出结果:110
#define A(a) (a+a)
#define B(b) A(b) * b
printf("%d\n", B(10))
编译预处理和动态存储分配
2018/11/15
甘肃联合大学 电信学院 曹晓丽
第一节 编译预处理
一、宏替换
宏替换是用#define指定的预处理 1.不带参数的宏定义 1> 不带参数的宏定义命令行形式 #define 宏名 替换文本 或 #define 宏名
2018/11/15
甘肃联合大学 电信学院 曹晓丽
第一节 编译预处理
2018/11/15
甘肃联合大学 电信学院 曹晓丽
第一节 编译预处理
5> 替换文本不能替换双引号中与宏名相同的字符 串。如:#define YES 1 则不能用1来替换printf(“YES”);当中的YES 6> 替换文本不能替换用户标识符中的成分 如:#define YES 1 int YESORNO; 此处YES不替换 7> 宏名通常用大写字母,但非规定 8> 宏定义一般写在程序开头 9> 宏名不能用双引号引起来 #define “YES” 1 将不进行宏替丽
第一节 编译预处理
5> 宏替换和函数调用有相似之处,但宏替换对参 数无类型要求,整型也可,实型也可;函数调 用中,对不同类型的参数,需定义不同的函数。 6> 宏替换是在编译时由预处理程序完成的,不占 运行时间,但需占用大量空间;函数调用是程 序运行时进行的,需占运行时间,但不需占用 大量空间。 7> 宏替换中,实参不能替换双引号中的形参 例 : #define LET(x,v) x=v #define PRT(f,i) printf(f,i)
第十三章 编译预处理和 动态存储分配
2018/11/15
甘肃联合大学 电信学院 曹晓丽
第一节 编译预处理
编译预处理:C编译程序对C源程序进行编译 之前,由编译预处理程序对编译预处理命令进行 处理的过程 C语言中,凡是以“#”开头的行,都称为“编 译预处理”命令行,每行的末尾不得用“;”号 结束,以区别于C语言中的语句、定义和说明语 句。它们可以出现在程序的任何一行的开始位置, 作用域是从出现点到本文件末尾。
编译预处理和动态存储分配_OK
4.一般包含用户自定义的.h文件用“ ”
8
动态存储分配
“静态存储分配”: 空间一经分配,在变量或数组的生 存期内是固定不变的。
“动态存储分配”:在程序执行期间需要空间来存储数 据时,通过“申请”分配指定的内存空间;当有闲置 不用的空间时,可以随时将其释放.
#include <stdlib.h> 使用malloc()、calloc()分配空间 使用free()释放空间
9
例:动态分配空间存放整型数组,赋值并输出
#include <iostream.h>
第十三章 编译预处理和动态存储分配
2021/9/4
1
编译预处理
编译之前,先对程序中特殊命令进行“预处理”,然后再进行通常的编译处理,得到目标代 码。 C提供的预处理功能主要有以下三种:
1.宏定义; 2.文件包含; 3.条件编译。
2
3
宏定义
不带参数的宏定义
一般形式为 # define 标识符 字符串
11
for(int c=0;c<size;c++) p[c]=c*2;
for(int c=0;c<size;c++) cout<<p[c]<<“ ”;
cout<<endl;
10
free(p); } //释放堆内存
上题若采用calloc()分配内存,将 if((p=(int *)malloc(size*sizeof(int)) )==NULL) 改为 if((p=(int *)calloc(size, sizeof(int)) )==NULL) 即可 两者返回未定类型的指针(地址)void*。
【全版】预处理和动态存储分配推荐PPT
由于C的库函数很多,将这些函数根据类型不同分类, 分别放在不同的文件中(例如, 数学函数:math.
printf(“\n”); pi=(int *)malloc( sizeof(int) );
#define S “%s”
} { float x,y;
1) 宏替换不占程序运行时间,只占编译时间。 存储分配
(2) 带参数的宏定义形式
#define 宏名(形参表) 替换文本 其中:宏名 是用户定义的标识符。
形参表 指定的形参(由标识符命名),形参之 间用逗号分开。
替换文本 是字符串(通常包含指定的形参)。 作用:编译预处理程序对源程序中出现的带实参的宏
,用实参对#define命令行中的替换文本(字符 串)中形参进行替换。 例如:#define F(x,y) x*x+y*y
数没有类型的要求。 4)宏替换中,实参不能替换双引号中的形参。 5)与不带参数的宏定义一样,同一个宏名不能重复定
义。 (3) 终止宏定义形式
#undef 已定义宏名
例如: #define PI 3.14159
main( ) ┆
#undef PI
从终止宏定义(#undef PI)后PI无定义,不代表 3.14159了。
第13章 编译预处理和动态
存储分配
上机过程:
高级语言ห้องสมุดไป่ตู้的源程序
编译、 连接
编译预处理
目标代码。
13.1 编译预处理
在C编译程序对源程序进行编译前,由编译预处理 程序对预处理命令行( 以#号开始的预处理命令行 )进行 处理, 然后对预处理后的源程序进行编译、连接,产生 可执行的目标代码。
C主要提供三种预处理命令: 宏定义、文件包含 和 条件编译。本章重点介绍前两种。
计算机二级C语言第12章 编译预处理与动态存储分配
正确答案:D 【解析】ANSI C标准规定malloc函数的返回值类型为void *,要是p指向double类型的动态存储单 元,需要使用强制类型转换double *,本题答案为D。
假设short int型数据占2字节、float型数据占4字节存储单元,则以下程序段将使Pi指向一个short int类型的存 储单元,使pf指向一个float类型的存储单元: short int *pi; float * pf; pi = ( short * ) malloc ( 2 ); pf = ( float * ) malloc(4); malloc函数返回的指针为void *(无值型),在调用函数时,必须利用强制类型转换将其转成所需的类型。上面的 程序段中,调用malloc函数时括号中的*号不可少,否则就转换成普通变量类型而不是指针类型了。
C语言中还有一种称作“动态存储分配”的内存空间分配方式:在程序执行期间需要空间来 存储数据时, 通过“申请”得到指定的内存空间;当有闲置不用的空间时,可以随时将其释放,由系统另作他用。
malloc函数
函数的调用形式为:malloc ( size)。
该函数包含在头文件stdlib.h里,返回值的类型为void *, malloc函数用来分配size个字节的存储区,返回一 个指向存储区首地址的基类型为void的地址。若没有足够的内存单元供分配,函数返回空(null)。
目录页
CONTENTS PAGE
计算机二级C语言 第12章 编译预处理与动态存储分配
所谓“编译预处理”就是在C编译程序对C源程序进行编译前,由编译预处理程序对这些编译预处理命 令行进行处理的过程。 预处理命令行必须在一行的开头以“#”号开始,每行的末尾不得用“;”号结束。 这些命令行的语法与C语言中其他部分的语法无关。根据需要,命令行可以出现在程序的任何一行的开 始部位,其作用一直持续到源文件的末尾。 重点是:#define 和 #include 命令行
C语言编译预处理和动态存储分配
编译预处理和动态存储分配考点一编译预处理在C语言中,凡是以“#”号开头的行,都称为编译预处理行。
所谓编译预处理就是在C语言编译程序对源程序进行编译前,由编译预处理程序对这些编译预处理命令进行处理的过程。
C语言有12中预处理命令:#define、#undef、#include、#if、#elif、#endif、#ifdef、#ifndef、#line、#line、#pragma、#error。
这些预处理命令行必须在一行的开头以“#”号开始,每行的末尾不能用“;”结束,以此来区别c语句。
根据需要,命令行可以出现在程序的任何一行的开始部位,其作用一直持续到源文件的末尾。
考点二宏替换(1)不带参数的宏定义格式:#define 宏名替换文本或#define 宏名(在define、宏名和替换文本之间用空格隔开;#define 命令行可以不包含“替换文本”,这仅表示标识符被定义)。
注意:1:替换文本中可以包含已定义过的宏名;2:当宏定义在一行中写不下,需要在下一行继续时,只需在最后一个字符紧接着加一个反斜线”\”;3:同一个宏名不能重复定义,除非两个宏定义命令行完全一致4:替换文本不能替换双括号中与宏名相同的字符串;5:替换文本并不替换用户标识符中的成分;6:用作宏名的的标识符通常用大写字母表示,不过这并不是语法规定,只是一种习惯,以便与程序中其他标识符相区分;7:在C语言中,宏定义的位置一般都写在程序开头.(2)带参数的宏定义格式:#define 宏名(形参表)替换文本例如:#define M(x,y)((x)*(y))在这个宏定义命令中,M(x,y)简称为”宏”,其中M是一个用户标识符,称为宏名,宏名和其后的括号必须紧挨着不能有空格,其后一对圆括号内是形参,形参之间用逗号隔开,替换文本中通常应该包含形参。
注意事项:1:同一个宏名不能重复定义,除非两个宏定义命令行完全一致;2:在调用带参数的宏名时,一对圆括号必不可少,圆括号中实参的个数应该与形参个数相同,在预编译时,编译预处理程序用替换文本来替换宏,并用对应的实参来替换形参;3: 替换文本的形参和整个表达式应该用括号括起来;4: 宏替换是在编译前由预处理程序完成的,因此宏替换不占运行时间;5: 宏替换中,实参不能替换双引号中的形参。
编译原理第9篇
编译原理
第37页
编译原理
第38页
编译原理
二、嵌套层次显示表(display)和活动记录
为了提高访问非局部量的速度,还可以引用一个 指针数组,称为嵌套层次显示表。 每进入一个过程后,在建立它的活动记录区的同 时建立一张嵌套层次表display. 假定现进入的过程的层数为i,则它的display表 含有i+1个单元。 此表本身是一个小找,自顶向下每个单元依次存 放着现行层,直接外层,…,直至最外层(0层, 主程序层)等每一层过程的最新活动记录的基地 址。
第25页
编译原理 进入过程P后所做工作示意
P的数组区
第26页
返回地址
1 0
TOP
SP
P的活动记录 (长度为L)
调用过程
编译原理
(3)过程返回
C语言以及其它一些相似的语言含有return(E)的返 回语句,E为表达式。
假定E值已计算出来并已存放在某临时单元T中,可 将T只传送到某个特定寄存器(调用过程将从这个特 定的寄存器中获得P的结果)。
第14页
编译原理 简单的栈式存贮分配
适用于简单程序语言的实现:语言没有分程序结构, 过程定义不允许嵌套,但允许过程的递归调用,允许 过程含有可变数组。 C语言就是这样一种语言。其局部名称的存储分配, 可以直接采用栈式存储分配策略。
第15页
编译原理
1、栈式存储分配
使用栈式存储分配法意味着把存储组成一个栈。 运行时,每当进入一个过程(一个新的活动开 始)时,就把它的活动记录压入栈,从而形成 过程工作时的数据区,一个过程的活动记录的 体积在编译时是可静态确定的。 当该活动结束(过程退出)时,再把它的活动 记录弹出栈,这样,它在栈顶上的数据区也随 即不复存在。
2020全国计算机等级考试二级C语言知识点全套复习提纲(精华版)
考点 1 程序设计 .....14 第 3 章 选择结构 ......19
考点 2 C 程序的结构
考点 1 关系运算符和关
和格式 ......................14 系表达式 ...................19
考点 3 常量和变量 . 14 考点 2 逻辑运算符和逻
考点 4 算术表达式 . 15 辑表达式 ...................19
....................................5. 考点 3 面向对象的程序 设计 .............................5 第 3 章 . 软件工程基础
5 考点 1 软件工程基本概 念 .................................5 考点 2 软件分析方法 6 考点 3 结构化设计方法 ....................................7. 考点 4 软件测试 .......8 考点 5 程序的调试 ...9 第 4 章 数据库设计基础
全国计算机等级考试二级
C语言全套复习提纲(精华 版)
目录
第一部分 公共
与风格 .........................4
基础知识
考点 2 结构化程序设计
第 1 章 算法与数据结 构 ..................................1.
考点 1 算法 ................1 考点 2 数据结构 .......1 考点 3 线性表及其顺 序存储结构 ................1 考点 4 栈和队列 .......1 考点 5 线性链表 .......2 考点 6 树与二叉树 ...2 考点 7 查找技术 .......3 考点 8 排序技术 .......3 第 2 章 程序设计基础 . 4 考点 1 程序设计方法
编译预处理和动态存储分配及答案
编译预处理和动态存储分配及答案编译预处理和动态存储分配一、选择题(1)有以下程序 main(){ char p[]={'a', 'b', 'c'}, q[]=\ printf(\ %d\\n\ };程序运行后的输出结果是 A)4 4 B)3 3 C)3 4 D)4 3(2)有以下程序# define f(x) (x*x) main(){ int i1, i2;i1=f(8)/f(4) ; i2=f(4+4)/f(2+2) ; printf(\ }程序运行后的输出结果是 A)64, 28 B)4, 4 C)4, 3 D)64, 64(3)有以下程序 main(){ char a[7]=\ i,j; i=sizeof(a); j=strlen(a); printf(\ %d\\n\}程序运行后的输出结果是 A)2 2 B)7 6 C)7 2 D)6 2(4)以下叙述中正确的是 A)预处理命令行必须位于源文件的开头B)在源文件的一行上可以有多条预处理命令 C)宏名必须用大写字母表示 D)宏替换不占用程序的运行时间(5) 有以下程序 main( ){ char a[]=”abcdefg”,b[10]=”abcdefg”;printf(“%d %d\\n”,sizeof(A) ,sizeof(B) ); }执行后输出结果是 A) 7 7 B) 8 8 C) 8 10 D) 10 10(6) 有以下程序#define f(x) x*x main( ) { int i;i=f(4+4)/f(2+2); printf(“%d\\n”,i); }执行后输出结果是 A) 28 B) 22 C) 16 D) 4(7) 有以下程序 #include #define F(X,Y) (X)*(Y) main (){ int a=3, b=4;printf(\}程序运行后的输出结果是 A) 12 B) 15 C) 16 D) 20(8) 有以下程序main(){ char s[]=\printf(\}执行后输出结果是A) 赋初值的字符串有错 B) 6,7 C) 5,6 D) 6,6(9) 有以下程序main(int arge,char *argv[]) { int n,i=0; while(arv[1][i]!='\\0'{ n=fun(); i++;} printf(%d\\n\}int fun(){ static int s=0; s+=1; return s; }假设程序经编译、连接后生成可执行文件exam.exe,若键入以下命令行 exam 123 则运行结果为(10) 有以下程序 main(){ char a[ ]={‘a’,‘b’,‘c’,‘d’, ‘e’, ‘f’, ‘g’,‘h’,‘\\0’};inti=sizeof(a); j=strlen(a); printf(“%d,%d\\b”i,j); }程序运行后的输出结果是 A)9,9 B)8,9 C)1,8 D)9,8(11) 程序中头文件typel.h 的内容是: #define N 5 #define M1 N*3 程序如下:i,j; #define “type1.h” #define M2 N*2 main() { int i;i=M1+M2; printf(“%d\\n”,i); }程序编译后运行的输出结果是: A) 10 B) 20 C) 25 D) 30(12) 有以下程序 #include main() { char *p,*q;p=(char*)malloc(sizeof(char)*20); q=p; scanf(“%s%s”,p,q);printf(“%s%s\\n”,p,q); }若从键盘输入:abc def,则输出结果是: A) def def B) abc def C) abc d D) d d(13) 若指针p已正确定义,要使p指向两个连续的整型动态存储单元,不正确的语句是 A) p=2*(int*)malloc(sizeof(int)); B) p=(int*)malloc(2*sizeof(int)); C) p=(int*)malloc(2*2);D) p=(int*)calloc(2,sizeof(int));(14) 以下程序的输出结果是 main(){ char st[20]= “hello\\0\\t\\\\\\”; printf(%d %d\\n”,strlen(st),sizeof(st)); }A) 9 9 B) 5 20C) 13 20 D) 20 20(15) 以下程序的输出结果是amovep(int p, int (a)[3],int n) { int i, j; for( i=0;i 感谢您的阅读,祝您生活愉快。
《全国计算机等级考试一本通:二级C语言》读书笔记模板
第12章文件
12.1 C语言文件的概念 12.2文件的打开与关闭 12.3文件的读、写 12.4文件的定位 12.5综合自测
第13章操作题高频考点精讲
13.1 C程序设计基础 13.2 C语言的基本结构 13.3函数 13.4指针 13.5数组 13.6字符串 13.7结构体、共用体和用户定义类型 13.8文件
3.1 C语言运算符 3.2算术运算符和算术表达式 3.3赋值运算符和赋值表达式 3.4位运算 3.5综合自测
第4章基本语句
4.1 C语句概述 4.2赋值语句与输入/输出 4.3综合自测
第5章选择结构
5.1关系运算符和关系表达式 5.2逻辑运算符和逻辑表达式 5.3 if语句和用if语句构成的选择结构 5.4 switch语句 5.5综合自测
这是《全国计算机等级考试一本通:二级C语言》的读书笔记模板,暂无该书作者的介绍。
谢谢观看
第14章无纸化真考题 库
附录 光盘链接
第0章考试指南
0.1考试环境简介 0.2考试流程演示
第1章公共基础知识
1.1数据结构与算法 1.2程序设计基础 1.3软件工程基础 1.4数据库言概述
2.1语言基础知识 2. 2常量、变量和数据类型 2.3综合自测
第3章运算符与表达式
第14章无纸化真考题库
14.1无纸化真考试题 14.2参考答案及解析
读书笔记
读书笔记
这是《全国计算机等级考试一本通:二级C语言》的读书笔记模板,可以替换为自己的心得。
精彩摘录
精彩摘录
这是《全国计算机等级考试一本通:二级C语言》的读书笔记模板,可以替换为自己的精彩内容摘录。
作者介绍
同名作者介绍
第6章循环结构
第十章 预编译处理和动态存储分配
10.1 编译预处理
所谓编译预处理是指,在对源程序进行编译 之前,先对源程序中的编译预处理命令进行处理; 然后再将处理的结果,和源程序一起进行编译, 以得到目标代码。 编译预处理是C语言编译系统的一个组成部分。 编译预处理是在编译前由编译系统中的预处理程
序对源程序的预处理命令进行加工。
编译预处理时,将程序中 PI用3.1415926代替,与 宏调用的过程相反,这种 将宏名替换成字符串的过 程称为“宏展开”。
注意:
(1)C语言中,用宏名替换一个字符串是简单的转换过程, 不作语法检查。若将宏体的字符串中符号写错了,宏展开时 照样代入,只有在编译宏展开后的源程序时才会提示语法错 误。例如:
例 求a,b,c三个数中最大者。
#include <stdio.h>
#define MAX(a,b) (a>b)?a:b
void main() {int a,b,c,max; scanf("%d%d%d",&a,&b,&c); max=MAX(a,b); max=MAX(max,c); printf("max=%d\n",max); }
程序运行结果:
4 6 2 max=6
3.带参数的宏与函数的区别
虽然有参宏与有参函数确实有相似之处,但不同之处更多, 主要有以下几个方面: 1)调用有参函数时,是先求出实参的值,然后再复制一份 给形参。而展开有参宏时,只是将实参简单地置换形参。
2)在有参函数中,形参是有类型的,所以要求实参的类型 与其一致;而在有参宏中,形参是没有类型信息的,因此用于 置换的实参,什么类型都可以。有时,可利用有参宏的这一特 性,实现通用函数功能。
C语言编译预处理和动态存储分配
C语言编译预处理和动态存储分配C语言编译预处理和动态存储分配引导语:你知道编译预处理和动态存储分配是什么意思吗?以下是店铺分享给大家的C语言编译预处理和动态存储分配,欢迎大家阅读学习!1.1宏定义(不带参数的宏定义,带参数的宏定义)1.编译预处理就是对C源程序进行编译前,由″编译预处理程序″对预处理命令行进行处理的过程。
2.C语言中,凡是以″#″开头的行,都称为″编译预处理″命令行。
C 语言中的编译预处命令有:#define,#undef,#include,#if,#else,#elif,#endif,#ifdef,#ifndef,#line, #pragma,#error。
这些预处理命令组成的预处理命令行必须在一行的开头以″#″号开始,每行的未尾不得加″;″号,以区别于C语句、定义和说明语句。
3.不带参数的宏定义:命令的一般形式为:#define标识符字符串定义中的″标识符″为用户定义的标识符,称为宏名。
在预编译时,C预编译程序将出现的宏名替换成″字符串″的内容,这一过程也称为宏展开。
4.带参数的宏定义:命令的一般形式为#define宏名(形式参数)字符串定义中的.″字符串″应包含括号中所指定的形式参数。
注意宏名与括号之间不要加空格,否则就成为不带参数的宏定义了。
5.预编译时,遇到带实参的宏名,则按命令行中指定的字符串从左到右进行置换,原则是:遇到实参则以实参代替,非形参字符原样保留,从而成展开后的内容。
1.2“文件包含”处理1.文件包含的一般形式为:#include″头文件名″#include<头文件名>头文件名一般由C语言提供,也可以是用户自己编写的,头文件通常用.h作为后缀。
2.当头文件名用双引号括起来时,系统首先在使用此命令的文件所在的目录中查找被包含的文件,找不到时,再按系统指定的标准方式检索其它目录;当头文件名用尖括号括起来时,则直接按系统指定的标准检索方式查找被包含的文件。
编译预处理和动态存储分配
#define是宏定义命令。
例:使用不带参数的宏定义
#include <stdio.h> #define PI 3.1415926 void main() { float l,s,r,v; printf("input radius:"); scanf("%f",&r); l=2.0*PI*r; s=PI*r*r; v=4.0/3*PI*r*r*r; printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v); }
带参数的宏和函数的区别
函数调用时,先求出实参表达式的值,然后代入形 参。而是要带参数的宏只是进行简单的字符替换。 函数调用是在程序运行时处理的,为形参分配临时 的内存单元。而宏展开则是在编译前进行的,在展 开时并不分配内存单元,不进行值的传递处理,也没 有“返回值”的概念。 对函数中的实参和形参类型要求一致。而宏名无类 型,它的参数也无类型,只是一个符号代表,展开 时代入指定的字符串即可。宏定义时,字符串可以是 任何类型的数据。 调用函数只可得到一个返回值,而用宏可以设法得 到几个结果。
说明:
1)对带参数的宏展开只是将语句中宏名后括号内的实 参字符串代替#define 命令行中的形参。 2) 在宏定义时,在宏名与带参数的括弧之间不应加空 格,否则将空格以后的字符都作为替代字符串的一部分。
#include <stdio.h> area=3.1415926*a*a; #define PI 3.1415926 #define S(r) PI*r*r 运行情况如下: void main() { float a , area ; r=3.600000 a=3.6; area=40.715038 area=S(a); printf("r=%f\narea=%f\n",a,area); }
C语言 选择题库第9章 编译预处理和动态存储分配
第9章编译预处理和动态存储分配1.以下叙述中正确的是()。
A) 在C语言中,预处理命令行都以"#"开头B) 预处理命令行必须位于C源程序的起始位置C) #include <stdio.h>必须放在C程序的开头D) C语言的预处理不能实现宏定义和条件编译的功能参考答案:A【解析】预处理命令是以"#"号开头的命令,它们不是C语言的可执行命令,这些命令应该在函数之外书写,一般在源文件的最前面书写,但不是必须在起始位置书写,所以B),C)错误。
C)语言的预处理能够实现宏定义和条件编译等功能,所以D)错误。
2.以下关于宏的叙述中正确的是()。
A) 宏替换没有数据类型限制B) 宏定义必须位于源程序中所有语句之前C) 宏名必须用大写字母表示D) 宏调用比函数调用耗费时间参考答案:A【解析】宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头,所以B)选项中宏定义必须位于源程序中所有语句之前是错误的。
宏名一般用大写,但不是必须用大写,所以C)选项错误。
宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值),所以D)选项错误。
3.有以下程序:#include <stdio.h>#define PT 3.5 ;#define S(x) PT*x*x ;main(){int a=1,b=2;printf("%4.1f\n" ,S(a+b));}程序运行后的输出结果是()。
A) 7.5 B) 31.5 C) 程序有错无输出结果D) 14.0参考答案:C【解析】宏定义不是C语句,末尾不需要有分号。
所以语句printf("%4.1f\n" ,S(a+b));展开后为printf("%4.1f\n" ,3.5;*a+b*a+b;);所以程序会出现语法错误。
第9章 编译预处理和动态存储分配
第九章 编译预处理和动态存储分配● 考核知识点宏定义、不带参数的宏定义、带参数的宏定义 ● 文件包含 ● 动态存储分配重要考点提示● 理解并会使用宏定义● 使用常用函数的“文件包含”9.1宏定义1.不带参数的宏定义不带参数的宏定义命令行形式如下:#define 宏名 替换文本 或#define 宏名 在define 宏名和宏替换文本之间要用空格隔开。
说明:宏名一般习惯用大写字母表示,宏替换的过程实质上是原样替换的过程。
宏定义可以差事少程序中重复办公室某些字符串的工作量。
注意:可以用#undef 命令终止宏定义的作用域。
例如: #define PI 3.14main() {}#undef PI在进行宏定义时,可以引用已定义的宏名,例如: #define R 15.5 #define PI 3.14 #define L 2*PI*R 2.带参数的宏定义定义的一般形式为:#define 宏名(参数表) 字符串宏定义不只进行简单的字符串替换,还要进行参数替换,例如: #define MV(x,y)((x)*(y)) ...a=MV(5,2);/*引用带参的宠名*/b=6MV(a+3,a);以上宏定义命令行中,MV (x,y )称为“宏”,其中MV 是一个用户标识符,称为宏名。
宏名和左括号“(”必须紧挨着,它们之间不能留有空格,其后圆括号中由称为形参的标识符组成,并且可以有多个形参,各参数之间用逗号隔开,“替换文本”中通常应该包含有形参。
执行过程:如果程序中有带实参的宏,则按#define 便衣行中指定的字符串从左到右进行了置换。
如果字符串中包含宏中的形参(如x,y ),则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。
如果宏定义中的字符串中的字符不是参数字符(如(x*y)中的“*”号),则保留。
这样就形成了置换的字符串。
提示:和不带参数的宏定义相同,同一个宏名不能重复定义。
在替换带参数的宏名时,圆括号必不可少。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.以下叙述中正确的是()。
A) 在C语言中,预处理命令行都以"#"开头B) 预处理命令行必须位于C源程序的起始位置C) #include <stdio.h>必须放在C程序的开头D) C语言的预处理不能实现宏定义和条件编译的功能参考答案:A【解析】预处理命令是以"#"号开头的命令,它们不是C语言的可执行命令,这些命令应该在函数之外书写,一般在源文件的最前面书写,但不是必须在起始位置书写,所以B),C)错误。
C)语言的预处理能够实现宏定义和条件编译等功能,所以D)错误。
2.以下关于宏的叙述中正确的是()。
A) 宏替换没有数据类型限制B) 宏定义必须位于源程序中所有语句之前C) 宏名必须用大写字母表示D) 宏调用比函数调用耗费时间参考答案:A【解析】宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头,所以B)选项中宏定义必须位于源程序中所有语句之前是错误的。
宏名一般用大写,但不是必须用大写,所以C)选项错误。
宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值),所以D)选项错误。
3.有以下程序:#include <stdio.h>#define PT 3.5 ;#define S(x) PT*x*x ;main(){int a=1,b=2;printf("%4.1f\n" ,S(a+b));}程序运行后的输出结果是()。
A) 7.5 B) 31.5 C) 程序有错无输出结果D) 14.0参考答案:C【解析】宏定义不是C语句,末尾不需要有分号。
所以语句printf("%4.1f\n" ,S(a+b));展开后为printf("%4.1f\n" ,3.5;*a+b*a+b;);所以程序会出现语法错误。
4.若程序中有宏定义行:#define N 100则以下叙述中正确的是A) 宏定义行中定义了标识符N的值为整数100B) 在编译程序对C源程序进行预处理时用100替换标识符NC) 上述宏定义行实现将100赋给标示符ND) 在运行时用100替换标识符N参考答案:B【解析】本题考查预编译相关知识,宏定义在编译程序时做了一个简单的替换,所以选项B正确。
5.有以下程序#include <stdio.h>#define N 3void fun( int a[][N], int b[] ){ int i, j;for( i=0; i<N; i++ ){ b[i] = a[i][0];for( j=1; j<N; j++ )if ( b[i] < a[i][j] ) b[i] = a[i][j];}}main(){ int x[N][N] = {1, 2, 3, 4, 5, 6, 7, 8, 9}, y[N] ,i;fun( x, y );for ( i=0; i<N; i++ ) printf( "%d,", y[i] );printf( "\n" );}程序运行后的输出结果是A) 3,5,7 B) 1,3,5, C) 2,4,8, D) 3,6,9,参考答案:D【解析】函数fun()的作用是求出二维数组a[][N]中每一行中的最大元素,所以在main()函数中执行完fun(x,y)后,数组y中的元素为二维数组x[N][N]每一行的最大元素。
因此D选项正确。
6.下列选项中,能正确定义数组的语句是A) intnum[0...2008]; B) intnum[]; C) int N=2008; D) #define N 2008intnum[N]; intnum[N];参考答案:D【解析】C语言不允许定义动态数组,定义数组的大小必须为常量表达式。
A选项错误,C语言中数组没有此类型的定义方法;B选项错误,定义数组应指明数组大小,如果不指明数组大小,需要给定初值的个数;C选项错误,N为变量,不能用来定义数组大小。
因此D选项正确。
7.若要求定义具有10个int型元素的一维数组a,则以下定义语句中错误的是A) #define n 5 B) int n=10,a[n]; C) int a[5+5];D) #define N 10int a [2*n]; int a[N];参考答案:B【解析】一维数组的定义方式为:类型说明符数组名[常量表达式];注意定义数组时,元素个数不能是变量。
因此应该选B选项。
8.有以下程序#include <stdio.h>#define N 4void fun(int a[][N], int b[]){ int i;for(i=0;i<N;i++) b[i] = a[i][i];}main(){ int x[][N]={{1,2,3},{4}, {5,6,7,8},{9,10}}, y[N], i;fun(x, y);for (i=0;i<N; i++) printf("%d,", y[i]);printf("\n");}程序的运行结果是A) 1,0,7,0, B) 1,2,3,4, C) 1,4,5,9, D) 3,4,8,10,参考答案:A【解析】该程序首先在定义变量时,对二维数组x[][N]进行赋值操作;调用函数fun,函数fun的功能是将二维数组中的a[0][0]、a[1][1]、a[2][2]和a[3][3]赋值给一维数组。
最后将一维数组1,0,7,0,输出。
9.若有以下程序#include <stdio.h>#define N 4void fun( int a[][N], int b[], int flag ){ inti,j;for( i=0; i<N; i++ ){ b[i] = a[0][i];for( j=1; j<N; j++ )if (flag ? (b[i] > a[j][i]) : (b[i] < a[j][i])) b[i] = a[j][i];}}main(){ int x[N][N]={1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16}, y[N],i;fun(x, y, 1);for (i=0;i<N; i++) printf("%d,", y[i]);fun(x, y, 0);for (i=0;i<N; i++) printf("%d,", y[i]);printf("\n");}则程序的输出结果是A) 4,8,12,16,1,5,9,13, B) 1,2,3,4,13,14,15,16,C) 1,5,9,13,4,8,12,16, D) 13,14,15,16,1,2,3,4,参考答案:B【解析】该题首先初始化二维数组,if (flag ? (b[i] > a[i][j]) : (b[i] < a[i][j]))条件语句的条件表达式使用了条件运算符构成的选择结构,即flag为真时,以(b[i] > a[i][j])作为条件表达式的值,否则以(b[i] < a[i][j])作为条件表达式的值,fun函数功能是给一维数组赋值。
fun(x, y, 1);该函数调用后,即当flag为真时,使一维数组获得二维数组第1行的数值;fun(x, y, 0);该函数调用后,即当flag为假时,使一维数组获得二维数组第4行的数值;因此B选项正确。
10.若有以下程序#include <stdio.h>#define N 4void fun(int a[][N], int b[], int flag){ inti,j;for(i=0; i<N; i++){ b[i] = a[i][0];for(j=1; j<N; j++)if (flag ? (b[i] > a[i][j]) : (b[i] < a[i][j]))b[i] = a[i][j];}}main( ){ int x[N][N]={1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16}, y[N],i;fun(x, y, 1);for ( i=0; i<N; i++ ) printf("%d,", y[i]);fun(x, y, 0);for (i=0;i<N; i++) printf("%d,", y[i]);printf("\n");}则程序的输出结果是A) 1,5,9,13,4,8,12,16, B) 4,8,12,16,1,5,9,13,C) 1,2,3,4,13,14,15,16, D) 13,14,15,16,1,2,3,4,参考答案:A【解析】该题首先初始化二维数组,if (flag ? (b[i] > a[i][j]) : (b[i] < a[i][j]))条件语句的条件表达式使用了条件运算符构成的选择结构,即flag为真时,以(b[i] > a[i][j])作为条件表达式的值,否则以(b[i] < a[i][j])作为条件表达式的值,fun函数功能是给一维数组赋值。fun(x, y, 1);该函数调用后,即当flag为真时,使一维数组获得二维数组第1列的数值;fun(x, y, 0);该函数调用后,即当flag为假时,使一维数组获得二维数组第4列的数值;因此A选项正确。11.有以下程序#include <stdio.h>#define S(x) 4*(x)*x+1main(){ int k=5, j=2;printf("%d\n", S(k+j) );}程序运行后的输出结果是A) 33 B) 197 C) 143 D) 28参考答案:C【解析】本题考查带参数的宏定义,S为带参数的宏定义,运行S(k+j)为4*(k+j)*k+j+1=143,选项C正确。
12.有以下程序#include <stdio.h>#define SUB(a) (a)-(a)main(){ int a=2,b=3,c=5,d;d=SUB(a+b)*c;printf("%d\n",d);}程序运行后的输出结果是A) 0 B) -12 C) -20 D) 10参考答案:C【解析】本题考查宏定义,宏定义只是做简单的替换,所以本题中SUB(a+b)*c=(a+b)-(a+b)*c=-20,所以答案为C选项。