第9章 编译预处理和动态存储分配
- 格式:docx
- 大小:49.31 KB
- 文档页数:7
第9章9.1 物理和虚拟(1)一个使用物理寻址的系统:当CPU执行这条加载指令时,它会产生一个有效的物理地址,通过存储器总线,把它传递给主存。
主存取出从物理地址4处开始的4字节的字,并将它返回给CPU,CPU会将它存放在一个寄存器里。
(2) 一个使用虚拟寻址的系统:使用虚拟寻址时,CPU通过生成一个虚拟地址来访问主存,这个虚拟地址在被送到存储器之前先转换成适当的物理地址。
(3)地址翻译:将一个虚拟地址转换为物理地址的任务。
存储器管理单元(MMU):利用存放在主存中的查询表来动态翻译地址。
9.2 地址空间(1)地址空间:一个非负整数地址的有序集合:{0,1,2,3,...}线性地址空间:地址空间的整数是连续的。
虚拟地址空间:在一个带虚拟存储器的系统中,CPU从一个N = 2n {0, 1, 2, 3, …, N-1}物理地址空间:{0, 1, 2, 3, …, M-1}(2)虚拟存储器的基本思想:允许每个数据对象有多个独立地址,其中每个地址都选自一个不同的地址空间。
(3)主存中的每个字节都有一个选自虚拟地址空间虚拟地址和一个选自物理地址空间的物理地址。
9.3 虚拟存储器作为缓存的工具(1)虚拟存储器(VM)被组织为一个有存放在磁盘上的N个连续的字节大小的单元组成的数组。
每个虚拟页的大小为P = 2p(2的p 次方)。
物理存储器杯分割为物理页(PP),大小也为P字节(物理页也称为页帧)(2)任意时刻,虚拟页面的集合都分成3个不相交的子集:未分配的:VM系统还有未分配(或创建)的页;不占任何磁盘空间缓存的:当前缓存在物理存储器中的已分配页。
未缓存的:没有缓存在物理存储器中的已分配页。
(3)DRAM缓存的组织结构:SRAM缓存:表示位于CPU和主存之间的L1、L2和L3高速缓存。
DRAM缓存:表示虚拟存储器系统的缓存,它在主存中缓存虚拟页。
(4)页表:页表就是一个页表条目(PTE)的数组。
每个PTE由一个有效位和一个n位地址字段组成的。
编译预处理和动态存储分配考点一编译预处理在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: 宏替换中,实参不能替换双引号中的形参。
编译预处理和动态存储分配及答案编译预处理和动态存储分配一、选择题(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语言编译预处理和动态存储分配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.当头文件名用双引号括起来时,系统首先在使用此命令的文件所在的目录中查找被包含的文件,找不到时,再按系统指定的标准方式检索其它目录;当头文件名用尖括号括起来时,则直接按系统指定的标准检索方式查找被包含的文件。
第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.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.以下叙述中正确的是()。
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) int num[0...2008]; B) int num[]; C) int N=2008; D) #define N 2008int num[N]; int num[N];参考答案:D【解析】C语言不允许定义动态数组,定义数组的大小必须为常量表达式。
A选项错误,C语言中数组没有此类型的定义方法;B选项错误,定义数组应指明数组大小,如果不指明数组大小,需要给定初值的个数;C选项错误,N为变量,不能用来定义数组大小。
因此D选项正确。
7.若要求定义具有10个int型元素的一维数组a,则以下定义语句中错误的是A) #define n 5B) 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 ){ int i,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){ int i,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选项。