第8章 编译预处理(课件)-《C语言程序设计》同步教学(清华大学出版)

2024-08-12
| 35页
| 82人阅读
| 21人下载
普通

内容正文:

(清华大学出版) 《C语言程序设计》 同步教学 * 第八章 编译预处理 第8章 编译预处理 8.1 宏定义 8.2 文件包含 8.3 条件编译 * C语言提供的编译预处理命令主要有以下三种: (1) 宏定义。 (2) 文件包含。 (3) 条件编译。 第八章 编译预处理 * 8.1.1 不带参数的宏定义 8.1 宏定义 #define 宏名 字符串 标识符 例如: #define PI 3.1415926 宏展开: 将宏名替换成字符串的过程 第八章 编译预处理 * (1) 宏名一般习惯用大写字母表示。 (2) 一个宏名只能被定义一次。 (3) 在进行宏定义时,可以引用已定义的宏名。 (4) 对在字符串常量及用户标识符中,与宏名相同的部分不作 替换。 例如:已定义 #define L 1234 在程序中有变量 Length,其中 L 不作替换。同样在 printf("L= %f",…)中的L不作替换。 (5) 宏定义的作用域:从定义开始到程序结束。 (6) 当宏定义在一行写不下,换行时需在行尾加换行字符"\"。 8.1.1 不带参数的宏定义 第八章 编译预处理 * 【 例8.1】使用宏定义的例子。 #include<stdio.h> #define R 3.0 #define PI 3.1415926 #define L 2*PI*R #define S PI*R*R void main() { printf("L=%.2f S=%.2f ",L,S); } 第八章 编译预处理 * #define 宏名(形参表) 字符串 例如: #define M(a,b) a*b area=M(3,7); 宏展开:area=3*7; 【例8.2】 分析下面程序的执行结 果。 #include <stdio.h> #define M(x,y) (x*y) void main() { int a = 2, b = 3, c, d; c = M(a,b); /* c = (a*b) */ d = M(a+1,b+1); /* d = (a+1*b+1) */ printf("c=%d, d=%d ",c,d); } 程序运行结果: c=6, d=6 (为什么?) 8.1.2 带参数的宏定义 第八章 编译预处理 * 宏调用:6/MU(2+3,4+5) 宏展开:6/((2+3)*(4+5)) 宏调用:6/MU(2+3,4+5) 宏展开:6/(2+3)*(4+5) 宏调用:6/MU(2+3,4+5) 宏展开:6/(2+3*4+5) 宏调用:6/MU(2+3,4+5) 宏展开:6/2+3*4+5 (2) 宏定义:#define MU(x,y) (x*y) (3) 宏定义:#define MU(x,y) (x)*(y) (4) 宏定义:#define MU(x,y) ((x)*(y)) 在使用带参数的宏时,要注意 括号 的使用!!! (1) 宏定义:#define MU(x,y) x*y 第八章 编译预处理 * 8.1.3 终止宏定义 #undef 宏名 例如: #define PI 3.14 void main() … #undef PI … 第八章 编译预处理 * 8.2 文件包含 文件包含(file inclusion) 预处理命令有两种格式: #include“文件名” #include<文件名> 如: #include<stdio.h> 在stdio.h文件中有: #define EOF -l #define NULL 0 当前目录 系统指定目录 系统指定目录 第八章 编译预处理 * 【例8.3】一个程序写在多个源文件中的应用举例。 经过编译预处理后: … … int fun1(int a,int b) { return a+b; } int fun2(int a,int b) { return a*b; } void main() { printf("%d ",fun1(3,5)); printf("%d ",fun2(3,5)); } 源文件ex803.c中的内容: #include<stdio.h> #include"ex803_1.c" #include"ex803_2.c" void main() {printf("%d ",fun1(3,5)); printf("%d ",fun2(3,5)); } 源文件ex803_1.c中的内容: int fun1(int a,int b) { return a+b;} 源文件ex803_2.c中的内容: int fun2(int a,int b) { return a*b;} 第八章 编译预处理 * 8.3 条件编译 源程序中的一部分内容只在满足一定条件才进行编译,或者,当条件成立时去编译一组语句,而当条件不成立时编译另一组语句,这就是“条件编译”。 条件编译命令有以下几种形式: #ifdef 标识符 程序段l #else 程序段2 #endif 第八章 编译预处理 * 第九章 指 针 第9章 指 针(Pointer) 9.1 指针概述 9.2 指针与一维数组 9.3 指针与二维数组 9.4 指针与字符串 9.5 指针与函数 9.6 指针数组与多级指针 * 第九章 指 针 #include <stdio.h> void main() { int m=0; int n=0; m=1; printf("Address of m and n is: %#xd,%#xd ",&m, &n); } 9.1 指针概述 内存 地址 地址 对内存单元的访问是通过地址实现的,地址“指向”要操作的内存单元。 内存单元的地址—指针 ! 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 0xFAC2AB2C 00000000 00000000 00000000 00000000 m 0xFAC2AB28 00000000 00000000 00000000 00000000 n 00000001 00000000 00000000 00000000 * 第九章 指 针 9.1 指针概述 指针变量(pointer): 一种特殊类型的变量,用于存放变量的地址,通常称为指针。 指针 是 一种 变量, 指针 是 一种 特殊类型 的 变量, 一个指针变量的值 是 另一个变量的地址。 * 第九章 指 针 如何声明 一个 指针变量? int *ptr; 指针变量的名称 指针变量的类型 ptr 是一个指向整型变量的指针 * 第九章 指 针 int x,*ptr; ptr = &x; ptr 是一个指向 整型变量x 的指针 如何对 一个指针变量 赋值? * 第九章 指 针 如何读写内存中的数据? 通过变量的地址访问变量所在的存储单元 两种寻址方式 直接(寻址)访问 直接按变量地址来存取变量内容的访问方式 间接(寻址)访问 通过指针变量来间接存取它所指向的变量的访问方式 寻址方式 * &:求地址运算符 *:指针运算符 若执行了p=&m,则 *p 与 m 等价, 都代表变量 m 的 存储单元 #include <stdio.h> void main() { int m = 0; int n = 0; int *p; /*求m的地址赋值给变量p */ p = &m; /* 给p所指向的变量赋值1*/ *p = 1; p = &n; *p = 2; /* 读取p所指向的变量的值*/ m = *p; printf("m=%d,n=%d",m, n); } 第九章 指 针 * #include <stdio.h> void main() { int m = 0; int n = 0; int *p; /*求m的地址赋值给变量p */ p = &m; /* 给p所指向的变量赋值1*/ *p = 1; p = &n; *p = 2; /* 读取p所指向的变量的值*/ m = *p; } 第九章 指 针 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 11001100 0xFAC2AB24 p 0xFAC2AB2C 00000000 00000000 00000000 00000000 m 0xFAC2AB28 00000000 00000000 00000000 00000000 n 00101100 10101011 11000010 11111010 00000001 00000000 00000000 00000000 00000010 00000000 00000000 00000000 00101000 10101011 11000010 11111010 00000010 00000000 00000000 00000000 * 注意事项: (1)* 用于定义指针变量,但指针变量名不带 *。 如 int *point_i; 定义的指针变量为 point_ i ,不是 *point_ i (2)一个指针变量只能指向同一类型的变量 如 int *p1,*p2; 类型标识符 int 是说明: 指针变量 p1 和 p2 所指向的变量类型为 int 型。 第九章 指 针 * (3)变量前面的 “*” 不能省略。 如: int *ptr1,ptr2; 则 ptr2 被定义为整型变量而非指针变量。 (4)定义指针变量后,并未确定该变量指向何处。 在引用指针变量前,必须让它指向一个变量。 int a=3; float x=2.5 ; int *p1,*p2; p1=&a; p2=&x; × √ 第九章 指 针 注意事项: * 在定义指针变量的同时, 可对其初始化。 int i, *ip=&i; 注意:i 的定义一定在 ip 定义之前。 假设 i 为整型变量,且有 int *p1,*p2; 则可通过下面四种方式为指针变量 p1 或 p2 赋值: 第九章 指 针 如何引用 一个指针变量? * 2. 使用取地址运算符,把地址值赋给指针变量。 p1=&i;(求出变量 i 的内存地址赋给p1)。 i 的地址赋予 p1 之后,*p1 总是与 i 等价。 3. 把指针变量的值直接赋给指针变量。 p1=&i,p2=p1;将使 p1 和 p2 均指向变量 i。 4. 给指针变量赋 NULL 值。 P1=NULL; 表示为指针 p1 赋了“空值”。 NULL 表示空指针,即无效指针;但它只是逻辑上无效,并不是真正地无效。 如何引用 一个指针变量? 第九章 指 针 * 5. 把数组的首地址赋予指向数组的指针变量。 int a[5], *pa; pa=a; ( 或pa=&a[0] )。 6. 把字符串首地址赋予指向字符类型的指针变量。 char *pc; pc= "c language " ; 或:char *pc = "c language"; 注意: 仅将首地址赋入,而不是将字符串"c language"赋予 pc 7. 将函数的入口地址赋予指向函数的指针变量。 int (*pf)( ); pf = f ; (f为函数名) 如何引用 一个指针变量? 第九章 指 针 * #include <stdio.h> main() { char ch='A'; char * ch_ptr ; ch_ptr=&ch; /*使ch_ptr指向ch*/ printf("ch=%c ",ch); printf("*ch_ptr=%c ",*ch_ptr); *ch_ptr='X'; /*间接改变ch的值*/ printf("ch=%c ",ch); printf("*ch_ptr=%c ",*ch_ptr); printf("address of ch is: %x ",ch_ptr); } /*输出ch的地址*/ 第九章 指 针 【例9.1】 * 将两个整型数a,b按由大到小次序输出。 #include <stdio.h> main( ) { int *p1, *p2, *p, a, b; scanf("%d,%d",&a,&b); p1=&a; p2=&b; if(a<b) { p=p1; p1=p2; p2=p; } printf("a=%d,b=%d ",a,b); printf("larger=%d,little=%d ",*p1,*p2); } 交换地址 按原序输出 由大到小 注意:a 和 b 并未交换,但 p1 和 p2 的值交换了。 【例9.2】 第九章 指 针 * 第九章 指 针 对 * 及 & 的说明:(同级运算,由右向左) 若pa=&a (将 a 的地址赋给指针变量pa), 则 &*pa  &(*pa)  &(a)  & a *&a  *(&a)  *pa  a (*pa)++  a++ *pa++  *(pa++) 注意:此时pa不再指向a * void Swap(int *x,int *y) { int temp; temp = *x; *x = *y; *y = temp; } main() { int a, b; a = 15; b = 8; Swap( &a, &b ); printf("a=%d,b=%d",a,b); } void Swap(int x,int y) { int temp; temp = x; x = y; y = temp; } main() { int a, b; a = 15; b = 8; Swap(a, b); printf("a=%d,b=%d",a,b); } 程序 1 程序 2 【例9.3】编写函数实现两数的互换。 实 参 形 参 结果有何不同? 第九章 指 针 主调函数 被调 函数 * 简单变量作函数参数 图 Swap函数调用前后参数变化的示意图 第九章 指 针 15 8 15 8 15 8 15 15 8 8 15 8 15 15 a) 调用Swap函数 (b)执行Swap函数 c) 从Swap函数返回 temp x y b main 函数 Swap 函数 ① ② ③ a a a temp temp x x y y b b * 指针变量作函数参数 第九章 指 针 15 8 8 15 &a &b &a &b 15 (a) 调用Swap函数 (b) 执行Swap函数 a a b b *x *x *y *y y y x x &a &b main 函数 Swap 函数 temp temp ② ① ③ 图 用指针变量作函数参数实现两数互换函数的示意图 * swap函数的几种错误形式(1/3) 参数单向传递 void Swap(int x, int y) { int temp; temp = x; /*x,y为内部变量*/ x = y; y = temp; } 第九章 指 针 * swap函数的几种错误形式(2/3) 参数单向传递 void Swap(int *p1, int *p2) { int *p; p = p1; /*p1,p2为内部变量*/ p1 = p2; p2 = p; } 第九章 指 针 * swap函数的几种错误形式(3/3) 指针 p 没有确切地址 void Swap(int *p1, int *p2) { int *p; /*指针p未初始化*/ *p = *p1; *p1 = *p2; *p2 = *p; } 第九章 指 针 * 谢谢观看 $$

资源预览图

第8章 编译预处理(课件)-《C语言程序设计》同步教学(清华大学出版)
1
第8章 编译预处理(课件)-《C语言程序设计》同步教学(清华大学出版)
2
第8章 编译预处理(课件)-《C语言程序设计》同步教学(清华大学出版)
3
第8章 编译预处理(课件)-《C语言程序设计》同步教学(清华大学出版)
4
第8章 编译预处理(课件)-《C语言程序设计》同步教学(清华大学出版)
5
第8章 编译预处理(课件)-《C语言程序设计》同步教学(清华大学出版)
6
所属专辑
由于学科网是一个信息分享及获取的平台,不确保部分用户上传资料的 来源及知识产权归属。如您发现相关资料侵犯您的合法权益,请联系学科网,我们核实后将及时进行处理。