收藏 分销(赏)

函数的递归调用重载默认参数省公共课一等奖全国赛课获奖课件.pptx

上传人:精**** 文档编号:2928272 上传时间:2024-06-11 格式:PPTX 页数:33 大小:176.44KB
下载 相关 举报
函数的递归调用重载默认参数省公共课一等奖全国赛课获奖课件.pptx_第1页
第1页 / 共33页
函数的递归调用重载默认参数省公共课一等奖全国赛课获奖课件.pptx_第2页
第2页 / 共33页
函数的递归调用重载默认参数省公共课一等奖全国赛课获奖课件.pptx_第3页
第3页 / 共33页
函数的递归调用重载默认参数省公共课一等奖全国赛课获奖课件.pptx_第4页
第4页 / 共33页
函数的递归调用重载默认参数省公共课一等奖全国赛课获奖课件.pptx_第5页
第5页 / 共33页
点击查看更多>>
资源描述

1、C+程序设计程序设计第第3章章(2)函数递归调用、重载、默认参数函数递归调用、重载、默认参数1第1页主要内容主要内容l函数递归调用函数递归调用l递归函数执行过程递归函数执行过程l函数重载函数重载l重载函数注意事项重载函数注意事项l带默认值形参带默认值形参l内联函数内联函数l程序多文件结构程序多文件结构l编译预处理编译预处理2第2页函数递归调用函数递归调用l函数递归调用:函数递归调用:直接递归调用:直接递归调用:指在一个函数指在一个函数A定义中,出现了调用本身定义中,出现了调用本身A情况,这种调用关系称为情况,这种调用关系称为直接递归调用,而函数直接递归调用,而函数A就是递归函数。就是递归函数。

2、间接递归调用:间接递归调用:指在一个函数指在一个函数A定义中,调用了函数定义中,调用了函数B,而在函数,而在函数B定义中又调用了定义中又调用了函数函数A,这种调用关系称为间接递归调用,而函数,这种调用关系称为间接递归调用,而函数A也是递归函数。也是递归函数。l递归算法关键在于:递归算法关键在于:确立递归公式确立递归公式 分析递归结束条件分析递归结束条件l递归函数设计普通方法:递归函数设计普通方法:先判断递归结束条件先判断递归结束条件 再进行递归调用再进行递归调用3第3页【例】(用递归算法求【例】(用递归算法求 n!。)分析:分析:确立递归公式:确立递归公式:n!=n (n-1)!分析递归结束条

3、件:当分析递归结束条件:当 n=0或或n=1 时,时,n!值为值为1。#include#include int fun (int n )/函数函数fun()功效是:求功效是:求n!if (n=0|n=1)return 1;/先判断递归结束条件先判断递归结束条件 return (n*fun(n-1);/再进行递归调用再进行递归调用void main()int n;cout n;if (n0)cout “输入数据有错!输入数据有错!”;exit(0);cout n “!=”fun(n)endl;运行:运行:请输入一个正整数:请输入一个正整数:3 3!=64第4页l main()函数函数调用调用 f

4、un(3)时执行过程:时执行过程:lmain()函数函数调用调用 fun(3)时栈中改变情况:时栈中改变情况:局部变量:局部变量:n=3执行:执行:cout fun(3)main()函数函数形参变量:形参变量:n=3执行:执行:return 3*fun(2)fun(3)函数函数形参变量:形参变量:n=2执行:执行:return 2*fun(1)fun(2)函数函数形参变量:形参变量:n=1执行:执行:return 1 fun(1)函数函数递推递推递推递推递推递推回归回归回归回归回归回归3操作系统执行操作系统执行状态和返回地址状态和返回地址main()局部变量局部变量n3操作系统执行操作系统执行

5、状态和返回地址状态和返回地址main()局部变量局部变量n3main()函数执行函数执行状态和返回地址状态和返回地址fun(3)形参变量形参变量n3操作系统执行操作系统执行状态和返回地址状态和返回地址main()局部变量局部变量n3main()函数执行函数执行状态和返回地址状态和返回地址fun(3)形参变量形参变量n2fun(3)函数执行函数执行状态和返回地址状态和返回地址fun(2)形参变量形参变量n3操作系统执行操作系统执行状态和返回地址状态和返回地址main()局部变量局部变量n3main()函数执行函数执行状态和返回地址状态和返回地址fun(3)形参变量形参变量n2fun(3)函数执行

6、函数执行状态和返回地址状态和返回地址fun(2)形参变量形参变量n1fun(2)函数执行函数执行状态和返回地址状态和返回地址fun(1)形参变量形参变量n5第5页递归函数执行过程递归函数执行过程l递归函数执行过程:递归函数执行过程:递归函数执行过程比较复杂,往往都存在着连续递归调用,其执行过程可分为递归函数执行过程比较复杂,往往都存在着连续递归调用,其执行过程可分为“递递推推”和和“回归回归”两个阶段,先是一次一次不停递推过程,直到符合递归结束条件,两个阶段,先是一次一次不停递推过程,直到符合递归结束条件,然后是一层一层回归过程。然后是一层一层回归过程。而其中每一次递归调用,系统都要在栈中分配

7、空间以保留该次调用返回地址、参数、而其中每一次递归调用,系统都要在栈中分配空间以保留该次调用返回地址、参数、局部变量,所以在递推阶段,栈空间一直处于增加状态,直到碰到递归结束条件,局部变量,所以在递推阶段,栈空间一直处于增加状态,直到碰到递归结束条件,然后进入回归阶段,栈空间反向依次释放。然后进入回归阶段,栈空间反向依次释放。在递归执行过程中,递归结束条件非常主要,它控制在递归执行过程中,递归结束条件非常主要,它控制“递推递推”过程终止,所以在任过程终止,所以在任何一个递归函数中,递归结束条件都是必不可少,不然将会一直何一个递归函数中,递归结束条件都是必不可少,不然将会一直“递推递推”下去。造

8、下去。造成无穷递归。成无穷递归。l递归算法缺点:递归算法缺点:内存消耗巨大,且连续地调用和返回操作占用较多内存消耗巨大,且连续地调用和返回操作占用较多CPU时间。时间。l递归算法优点:递归算法优点:算法描述简练易懂。算法描述简练易懂。6第6页【例】(分析下面递归函数执行过程,并给出程序运行结果。【例】(分析下面递归函数执行过程,并给出程序运行结果。)#include void sub(char c )cout c;if (c=a )return;sub(c-1);cout c;return;void main()char ch=e;sub(ch);运行:运行:e d c b a b c d e

9、局部变量:局部变量:ch=e执行:执行:sub(e)main()函数函数形参变量:形参变量:c=e执行:执行:cout c;sub(e-1)cout c returnsub(e)函数函数形参变量:形参变量:c=d执行:执行:cout c;sub(d-1)cout c returnsub(d)函数函数递推递推回归回归递推递推回归回归形参变量:形参变量:c=b执行:执行:cout c;sub(b-1)cout c returnsub(b)函数函数形参变量:形参变量:c=a执行:执行:cout c;if(c=a)returnsub(a)函数函数递推递推回归回归形参变量:形参变量:c=c执行:执行:c

10、out c;sub(c-1)cout c returnsub(c)函数函数递推递推回归回归递推递推回归回归7第7页【例】(用递归算法计算从【例】(用递归算法计算从n个人中选择个人中选择k个人组成一个委员会不一样组合数。个人组成一个委员会不一样组合数。)分析:分析:确立递归公式:确立递归公式:由由 n 人中选人中选 k 人组合数人组合数 =由由 n-1 人中选人中选 k 人组合数人组合数 +由由 n-1 人中选人中选 k-1 人组合数人组合数 分析递归结束条件:当分析递归结束条件:当 n=k 或或 k=0 时,组合数为时,组合数为1。#include#include int comm(int n

11、,int k )/函数函数comm()功效是:求功效是:求n人中选人中选k人组合数人组合数 if (nk)return 0;if (n=k|k=0)return 1;/先判断递归结束条件先判断递归结束条件 return (comm(n-1,k)+comm(n-1,k-1);/再进行递归调用再进行递归调用void main()int n,k;cout n k;if (n=0|k=0)cout “输入数据有错!输入数据有错!”;exit(0);cout “由由”n “人中选人中选”k “人组合数人组合数=”comm(n,k)endl;运行:运行:请输入正整数请输入正整数 n 和和 k:8 5 由由

12、8人中选人中选5人组合数人组合数=56 8第8页【例】(汉诺塔问题:有【例】(汉诺塔问题:有 A、B、C 三根柱子,三根柱子,A柱上有柱上有n个大小不等盘子,大盘在下,个大小不等盘子,大盘在下,小盘在上。要求将这小盘在上。要求将这n个盘子从个盘子从A柱移动到柱移动到C柱,在移动过程中能够借助柱,在移动过程中能够借助A、B、C 中中任何一根柱子,但每次只允许移动一个盘子,且在移动过程中三根柱子上都必须保任何一根柱子,但每次只允许移动一个盘子,且在移动过程中三根柱子上都必须保持大盘在下,小盘在上。)持大盘在下,小盘在上。)分析:分析:将将n个盘子从个盘子从A柱移动到柱移动到C柱可分解为以下三个步骤

13、:柱可分解为以下三个步骤:将将A 柱上柱上n-1个盘子移动到个盘子移动到 B柱(借助柱(借助C柱)柱)将将A柱上剩下一个盘子移动到柱上剩下一个盘子移动到C柱上柱上 将将n-1个盘子从个盘子从B柱上移动到柱上移动到C柱上(借助柱上(借助A柱)柱)分析得到,以上三个步骤包含两种操作:分析得到,以上三个步骤包含两种操作:将若干个盘子从一根柱上移动到另一根柱上,用递归函数将若干个盘子从一根柱上移动到另一根柱上,用递归函数 hanoi()实现。实现。将将1个盘子从一根柱上移动到另一根柱上,用函数个盘子从一根柱上移动到另一根柱上,用函数 move()实现。实现。A柱柱B柱柱C柱柱9第9页#include

14、void move(char get ,char put )/函数函数move()功效是:将一个盘子从功效是:将一个盘子从 get柱上移动到柱上移动到 put柱上柱上 cout get “柱柱 ”put “柱柱”endl;void hanoi(int n ,char one ,char two ,char three )/函数函数hanoi()功效是:将功效是:将n 个盘子从个盘子从one柱移动到柱移动到three柱(借助柱(借助two柱)柱)if (n=1 )move(one,three);return;/先判断递归结束条件先判断递归结束条件 else hanoi(n-1,one,three

15、,two);/将将one柱上柱上n-1个盘子移动到个盘子移动到two柱(借助柱(借助three柱)柱),进行递归调用进行递归调用 move(one,three);/将将one柱上剩下一个盘子移动到柱上剩下一个盘子移动到three柱上柱上 hanoi(n-1,two,one,three);/将将two柱上柱上n-1个盘子移动到个盘子移动到three柱(借助柱(借助one柱)柱),进行递归调用进行递归调用 10第10页void main()int n;cout n;cout “将将”n “个盘子从个盘子从A柱移动到柱移动到C柱步骤:柱步骤:”endl;hanoi(n,A,B,C);运行:运行:请输

16、入盘子数:请输入盘子数:4 将将4个盘子从个盘子从A柱移动到柱移动到C柱步骤:柱步骤:A柱柱 B柱柱 A柱柱 C柱柱 B柱柱 C柱柱 A柱柱 B柱柱 C柱柱 A柱柱 C柱柱 B柱柱 A柱柱 B柱柱 A柱柱 C柱柱 B柱柱 C柱柱 B柱柱 A柱柱 C柱柱 A柱柱 B柱柱 C柱柱 A柱柱 B柱柱 A柱柱 C柱柱 B柱柱 C柱柱11第11页函数重载函数重载l函数重载:函数重载:重载含义:重载含义:就是重新赋予新含义。在就是重新赋予新含义。在C+一个程序中能够用同一个函数名来命名多个一个程序中能够用同一个函数名来命名多个函数,这些同名函数在参数个数、类型上一定有所不一样,分别代表不一样函数,函数,这些

17、同名函数在参数个数、类型上一定有所不一样,分别代表不一样函数,当同名多个函数出现在同一个作用域内时,称为重载函数。当同名多个函数出现在同一个作用域内时,称为重载函数。重载目标:重载目标:程序中经常将功效相近函数在相同作用域内以相同函数名命名,从而形成程序中经常将功效相近函数在相同作用域内以相同函数名命名,从而形成重载函数,目标是方便使用,便于记忆。重载函数,目标是方便使用,便于记忆。【例】【例】int add(int x,int y );float add(float x,float y );float add(double x,double y );int add(int x,int y )

18、;int add(int x,int y,int z );int add(int x,int y,int z,int w );函数名相同,但参数类型不一样函数名相同,但参数类型不一样 函数名相同,但参数个数不一样函数名相同,但参数个数不一样12第12页重载函数注意事项重载函数注意事项l注意事项:注意事项:重载函数形参必须有所不一样:参数个数或参数类型不一样。重载函数形参必须有所不一样:参数个数或参数类型不一样。编译系统是依据实参加形参在类型及个数上最正确匹配来选择调用哪一个函数。编译系统是依据实参加形参在类型及个数上最正确匹配来选择调用哪一个函数。【例】【例】定义重载函数时,要防止二义性,以免

19、编译系统无法确定到底调用哪一个函数。定义重载函数时,要防止二义性,以免编译系统无法确定到底调用哪一个函数。【例】【例】int add(int x,int y );int add(int a,int b );编译器不以编译器不以形参名形参名来区分。来区分。int add(int x,int y );void add(int x,int y);编译器不以编译器不以返回值返回值来区分。来区分。int add(int x,int y );int add(char a,char b );当调用当调用 add(200,A)时,编译器无法确定到底调用哪一个函数。时,编译器无法确定到底调用哪一个函数。13第1

20、3页【例】【例】#include int add(int x,int y )/重载函数重载函数 cout “正在进行:两个正在进行:两个 int 型数据相加型数据相加!tt”;return (x+y);float add(float x,float y )/重载函数重载函数 cout “正在进行:两个正在进行:两个 float 型数据相加型数据相加!tt”;return (x+y);double add(double x,double y )/重载函数重载函数 cout “正在进行:两个正在进行:两个 double 型数据相加型数据相加!tt”;return (x+y);void main()

21、int a1=5,b1=8;float a2=5.1,b2=8.1;double a3=5.2,b3=8.2;cout add(a1,b1)endl;cout add(a2,b2)endl;cout add(a3,b3)endl;cout add(2,4)endl;cout add(2.1,4.1)endl;cout add(A,2)endl;运行:运行:正在进行:两个正在进行:两个 int 型数据相加型数据相加!13正在进行:两个正在进行:两个 float 型数据相加型数据相加!13.2正在进行:两个正在进行:两个 double 型数据相加型数据相加!13.4正在进行:两个正在进行:两个 i

22、nt 型数据相加型数据相加!6正在进行:两个正在进行:两个 double 型数据相加型数据相加!6.2正在进行:两个正在进行:两个 int 型数据相加型数据相加!11514第14页带默认值形参带默认值形参l默认形参值作用:默认形参值作用:函数申明时能够给形参指定一个默认值,调用时若给出实参,则函数申明时能够给形参指定一个默认值,调用时若给出实参,则形参采取实参值,若没有给出对应实参,则该形参采取预先给出默认值。形参采取实参值,若没有给出对应实参,则该形参采取预先给出默认值。【例】【例】#include int add(int x=10,int y=20 )/带默认形参值函数带默认形参值函数 c

23、out “正在进行:正在进行:”x “+”y “=”;return (x+y);void main()cout add(30,40)endl;cout add(50)endl;cout add()endl;cout add(2,4)endl;cout add(A,1)endl;cout add(A )endl;运行:运行:正在进行:正在进行:30+40=70正在进行:正在进行:50+20=70正在进行:正在进行:10+20=30正在进行:正在进行:50+4=54正在进行:正在进行:65+49=114正在进行:正在进行:65+20=8515第15页带默认值形参带默认值形参l带默认值形参申明次序:

24、带默认值形参申明次序:函数必须按函数必须按从右往左从右往左次序逐一申明带默认值形参,且在带次序逐一申明带默认值形参,且在带默认值形参右面不能出现不带默认值形参。只有这么要求后,在函数调用时才不会默认值形参右面不能出现不带默认值形参。只有这么要求后,在函数调用时才不会产生二义性。产生二义性。【例】【例】int add(int x,int y=2,int z=3 );当程序中调用当程序中调用 add(10)时,编译器调用时,编译器调用 add(10,2,3)。当程序中调用当程序中调用 add(10,20)时,编译器调用时,编译器调用 add(10,20,3)。int add(int x=1,int

25、 y,int z=3 );当程序中调用当程序中调用 add(10,20)时,编译器无法确定调用以下那一个:时,编译器无法确定调用以下那一个:add(10,20,3)或或 add(1,10,20)int add(int x=1,int y=2,int z=3 );当程序中调用当程序中调用 add()时,编译器调用时,编译器调用 add(1,2,3)。当程序中调用当程序中调用 add(10)时,编译器调用时,编译器调用 add(10,2,3)。当程序中调用当程序中调用 add(10,20)时,编译器调用时,编译器调用 add(10,20,3)。16第16页带默认值形参带默认值形参l默认形参值仅能申

26、明一次:默认形参值仅能申明一次:若函数定义在前、调用在后,默认形参值在函数定义时若函数定义在前、调用在后,默认形参值在函数定义时申明;若函数调用在前、定义在后,默认形参值必须在函数原型申明中给出,且在申明;若函数调用在前、定义在后,默认形参值必须在函数原型申明中给出,且在之后该函数定义时,不能再重复指定默认形参值。之后该函数定义时,不能再重复指定默认形参值。【例】【例】#include int add(int x=1,int y=2 );/带默认形参值函数原型申明带默认形参值函数原型申明void main()cout add(3,4)endl;cout add(5)endl;cout add(

27、)endl;int add(int x ,int y )/函数定义性申明函数定义性申明 cout “正在进行:正在进行:”x “+”y “=”;return (x+y);运行:运行:正在进行:正在进行:3+4=7正在进行:正在进行:5+2=7正在进行:正在进行:1+2=317第17页带默认值形参带默认值形参l默认形参值作用域:默认形参值作用域:同一个函数在相同作用域内,默认形参值应保持唯一,但在不同一个函数在相同作用域内,默认形参值应保持唯一,但在不一样作用域内,可提供不一样默认形参值。一样作用域内,可提供不一样默认形参值。【例】【例】#include int add(int x=1,int

28、y=2 );/函数函数add()全局原型申明全局原型申明void main()int add(int x=3,int y=4 );/函数函数add()局部原型申明局部原型申明 void fun();/函数函数fun()原型申明原型申明 cout add()endl;/使用局部默认形参值(实现使用局部默认形参值(实现3+4)fun();void fun()/函数函数fun()定义性申明定义性申明 cout add()endl;/使用全局默认形参值(实现使用全局默认形参值(实现1+2)cout add(10)endl;int add(int x ,int y )/函数函数add()定义性申明定义性

29、申明 cout “正在进行:正在进行:”x “+”y “=”;return (x+y);运行:运行:正在进行:正在进行:3+4=7正在进行:正在进行:1+2=3正在进行:正在进行:10+2=1218第18页内联函数内联函数l内联函数:内联函数:含义:含义:函数申明时前面加上函数申明时前面加上 inline 为内联函数,含义是向编译系统提议:编译时在为内联函数,含义是向编译系统提议:编译时在调用处用函数体进行置换,以节约了函数调用时控制转移、参数传递等开销。调用处用函数体进行置换,以节约了函数调用时控制转移、参数传递等开销。实质:实质:是使用空间换取时间方法,以加速程序执行,当出现屡次调用同一个

30、内联函数是使用空间换取时间方法,以加速程序执行,当出现屡次调用同一个内联函数时,程序本身占用空间有所增加,若内联函数仅调用一次时,并不增加程序本身占时,程序本身占用空间有所增加,若内联函数仅调用一次时,并不增加程序本身占用存放空间。用存放空间。注意:注意:对于用户指定内联函数,编译器是否作为内联函数来处理由编译器自行决定。对于用户指定内联函数,编译器是否作为内联函数来处理由编译器自行决定。另外内联函数体内不能有另外内联函数体内不能有循环循环、switch 等复杂结构控制语句。等复杂结构控制语句。【例】【例】#include inline float area(float r )/内联函数内联函

31、数 return (3.1415*r*r);void main()cout “半径半径=”3 “n面积面积=”area(3)endl;cout “半径半径=”5 “n面积面积=”area(5)endl;运行:运行:半径半径=3面积面积=28.2735半径半径=5面积面积=78.537519第19页程序多文件结构程序多文件结构l多文件程序:多文件程序:在在C+中,一个较大程序通常被分解为若干个源程序文件,然后分别对各个源程序文中,一个较大程序通常被分解为若干个源程序文件,然后分别对各个源程序文件单独进行编译,这些源程序文件由一个工程文件进行管理,最终连接成一个完整件单独进行编译,这些源程序文件由

32、一个工程文件进行管理,最终连接成一个完整程序。程序。在多文件组成程序中,一个源程序文件中定义全局变量或函数,在另外一个源程序文在多文件组成程序中,一个源程序文件中定义全局变量或函数,在另外一个源程序文件中被引用前,必须先对该全局变量或函数作外部申明。件中被引用前,必须先对该全局变量或函数作外部申明。外部类型变量申明格式:外部类型变量申明格式:extern 类型类型 全局变量名全局变量名;外部类型函数申明格式:外部类型函数申明格式:extern 函数原型申明函数原型申明;若一个源程序文件中定义全局变量或函数,仅限于该源程序文件中使用,不能被程序若一个源程序文件中定义全局变量或函数,仅限于该源程序

33、文件中使用,不能被程序中其它源程序文件使用,在定义该全局变量或函数时前面需加上中其它源程序文件使用,在定义该全局变量或函数时前面需加上static。内部类型变量申明格式:内部类型变量申明格式:static 类型类型 全局变量名全局变量名;内内部类型函数申明格式:部类型函数申明格式:static 函数原型申明函数原型申明;20第20页【例】(本程序由两个文件组成:【例】(本程序由两个文件组成:c1.cpp、c2.cpp)/文件文件c1.cpp内容内容#include int a=5;/定义定义a为普通全局变量,可拓展到外部文件使用为普通全局变量,可拓展到外部文件使用static int b=8;

34、/定义定义b为静态全局变量,只能在本文件中使用为静态全局变量,只能在本文件中使用extern int f0(int x );/函数函数f0()外部申明,其定义部分在外部申明,其定义部分在 c2.cpp 中中int f1(int x,int y )/函数函数f1()定义性申明,可拓展到外部文件使用定义性申明,可拓展到外部文件使用 cout “进入函数进入函数 f1()了了!t”;return (x+y+a+b);extern int f2(int x );/函数函数f2()外部申明,其定义部分在外部申明,其定义部分在 c2.cpp 中中extern int f3();/函数函数f3()外部申明,

35、其定义部分在外部申明,其定义部分在 c2.cpp 中中extern int f4(int x,int y);/函数函数f4()外部申明,其定义部分在外部申明,其定义部分在 c2.cpp 中中void main()/cout f0(7)endl;/此句编译经过,但连接犯错,此句编译经过,但连接犯错,f0()仅能在仅能在c2.cpp中使中使用用 cout f1(1,2)endl;cout f2(3)endl;cout f3()endl;cout f4(5,6)endl;运行:运行:进入函数进入函数 f1()了了!16进入函数进入函数 f2()了了!15进入函数进入函数 f3()了了!进入函数进入函

36、数 f0()了了!216进入函数进入函数 f4()了了!18021第21页/文件文件c2.cpp内容内容#include extern int a;/全局变量全局变量a 外部申明,其定义部分在外部申明,其定义部分在 c1.cpp 中中extern int b;/全局变量全局变量b 外部申明,其定义部分在外部申明,其定义部分在 c1.cpp 中中static int f0(int x )/函数函数f0()定义性申明,只能在本文件中使用定义性申明,只能在本文件中使用 cout “进入函数进入函数 f0()了了!t”;return (x*x);int f2(int x)/函数函数f2()定义性申明,

37、可拓展到外部文件使用定义性申明,可拓展到外部文件使用 cout “进入函数进入函数 f2()了了!t”;/b+;/此句编译经过,但连接犯错,此句编译经过,但连接犯错,b仅能在仅能在 c1.cpp 中使中使用用 return (x*a );int f3()/函数函数f3()定义性申明,可拓展到外部文件使用定义性申明,可拓展到外部文件使用 cout “进入函数进入函数 f3()了了!t”;return (f0(+a)*a );int f4(int x,int y )/函数函数f4()定义性申明,可拓展到外部文件使用定义性申明,可拓展到外部文件使用 cout “进入函数进入函数 f4()了了!t”;

38、return (x*y*a );22第22页编译预处理编译预处理l编译预处理:编译预处理:指源程序文件在被编译之前,由编译预处理程序对其所做加工处理工作。指源程序文件在被编译之前,由编译预处理程序对其所做加工处理工作。编译预处理程序不是编译预处理程序不是C+编译程序组成部分。编译程序组成部分。编译预处理程序在处理源程序文件时,是将预处理好程序写入到一个暂时文件中,并编译预处理程序在处理源程序文件时,是将预处理好程序写入到一个暂时文件中,并将该暂时文件作为编译程序输入文件,即编译程序是对该暂时文件进行编译,产生将该暂时文件作为编译程序输入文件,即编译程序是对该暂时文件进行编译,产生目标文件。目标

39、文件。编译预处理不会影响源程序文件中内容。编译预处理不会影响源程序文件中内容。l编译预处理命令:编译预处理命令:一律以一律以#开头,以回车符结束,末尾不加分号,且单独占用一行。开头,以回车符结束,末尾不加分号,且单独占用一行。编译预处理命令通常放在源程序文件开始部分。编译预处理命令通常放在源程序文件开始部分。l编译预处理命令有三种:编译预处理命令有三种:包含文件包含文件 宏定义宏定义 条件编译条件编译23第23页编译预处理编译预处理#include 命令命令l包含文件:包含文件:格式格式1:#include 格式格式2:#include “文件名文件名”处理过程:处理过程:将命令中所指定文件内

40、容嵌入到当前源程序文件该将命令中所指定文件内容嵌入到当前源程序文件该#include 命令处,成命令处,成为当前源程序文件一个组成部分。为当前源程序文件一个组成部分。#include :表示按标准方式查找,即从表示按标准方式查找,即从C+系统目录下系统目录下include子目录中子目录中开始查找所要包含文件。开始查找所要包含文件。C+库函数普通都存放在编译器约定库函数普通都存放在编译器约定include子目录下,当子目录下,当需要使用库函数时通常采取该格式。需要使用库函数时通常采取该格式。#include“文件名文件名”:表示先从当前目录(即当前源程序文件所在目录)开始查找表示先从当前目录(即

41、当前源程序文件所在目录)开始查找所要包含文件,若找不到,再按标准方式查找,到所要包含文件,若找不到,再按标准方式查找,到C+系统目录下系统目录下include子目录中子目录中继续查找。当需要包含用户自定义文件时,通常采取该格式。继续查找。当需要包含用户自定义文件时,通常采取该格式。#include“带路径文件名带路径文件名”:若所要包含文件既不在若所要包含文件既不在include子目录中,也不在当子目录中,也不在当前目录中,必须指明文件路径。前目录中,必须指明文件路径。例:例:#include “E:ABC123file1”24第24页编译预处理编译预处理#define 命令命令l不带参数宏定

42、义:不带参数宏定义:格式格式1:#define 宏名宏名 格式格式2:#define 宏名宏名 宏体宏体 处理过程:处理过程:定义一个宏名,若宏名后面跟有宏体,则将其后程序中全部出现该宏名地定义一个宏名,若宏名后面跟有宏体,则将其后程序中全部出现该宏名地方用对应宏体替换之,这种替换过程称为方用对应宏体替换之,这种替换过程称为“宏替换宏替换”或或“宏展开宏展开”。l几点说明:几点说明:宏名是一个标识符,通惯用大写字母表示,方便与程序中变量名区分。宏名是一个标识符,通惯用大写字母表示,方便与程序中变量名区分。宏定义能够出现在程序中任何位置,宏名作用域是从定义处开始到文件结尾处结束。宏定义能够出现在

43、程序中任何位置,宏名作用域是从定义处开始到文件结尾处结束。若要提前终止宏名作用域,可使用预处理命令:若要提前终止宏名作用域,可使用预处理命令:#undef 宏名宏名 在同一个作用域内,同一个宏名不允许定义两次或两次以上,不然编译预处理在进行在同一个作用域内,同一个宏名不允许定义两次或两次以上,不然编译预处理在进行宏替换时,会出现二义性。宏替换时,会出现二义性。在一个宏定义中能够使用前面已定义过宏名。在一个宏定义中能够使用前面已定义过宏名。25第25页编译预处理编译预处理#define 命令命令 宏替换时,只对宏名做简单替换,不做任何计算,也不做任何语法检验,若宏定义时宏替换时,只对宏名做简单替

44、换,不做任何计算,也不做任何语法检验,若宏定义时书写不正确,会得到不正确结果或编译时出现语法错误。书写不正确,会得到不正确结果或编译时出现语法错误。当宏名出现在字符串中时,编译预处理不进行宏替换。当宏名出现在字符串中时,编译预处理不进行宏替换。【例】【例】#include#define A 3+5#define B A*A /替换后:替换后:#define B 3+5*3+5#define C (A)*(A)/替换后:替换后:#define C (3+5)*(3+5)#define D “A”#define E “输出:输出:t”void main()cout E “B南南C京京A”endl;

45、/替换后:替换后:cout “输出:输出:t”“B南南C京京A”endl;cout E A endl;/替换后:替换后:cout “输出:输出:t”3+5 endl;cout E B endl;/替换后:替换后:cout “输出:输出:t”3+5*3+5 endl;cout E C endl;/替换后:替换后:cout “输出:输出:t”(3+5)*(3+5)endl;cout E D endl;/替换后:替换后:cout “输出:输出:t”“A”endl;运行:运行:输出:输出:B南南C京京A输出:输出:8输出:输出:23输出:输出:64输出:输出:A26第26页编译预处理编译预处理#def

46、ine 命令命令l带参数宏定义:带参数宏定义:格式:格式:#define 宏名宏名(形参表形参表)宏体宏体 形参表形参表由若干个参数名组成,参数之间以逗号分隔。由若干个参数名组成,参数之间以逗号分隔。宏体宏体由若干个参数组成一个式子。由若干个参数组成一个式子。处理过程:处理过程:类似于函数处理过程,先将宏调用中实参替换宏定义中形参,即先进行参类似于函数处理过程,先将宏调用中实参替换宏定义中形参,即先进行参数替换,再进行宏替换。数替换,再进行宏替换。l几点说明:几点说明:宏名是一个标识符,与后面形参表左括号之间不得有空格。宏名是一个标识符,与后面形参表左括号之间不得有空格。所谓参数替换,是指用宏

47、调用中每一个实参字符序列去替换宏定义中对应形参,且只所谓参数替换,是指用宏调用中每一个实参字符序列去替换宏定义中对应形参,且只做简单替换,不做任何计算做简单替换,不做任何计算。一个宏定义应在一行内定义完,以换行符结束,若多于一行在行尾加上转义符一个宏定义应在一行内定义完,以换行符结束,若多于一行在行尾加上转义符“”。27第27页【例】【例】#include#define PRINT(a)cout “a=”a endl;#define print(a,b)cout “ab=”a*b endl;cout “ab=”a/b endl;void main()int x,y;cout x y;PRINT

48、(x)/替换后:替换后:cout “a=”x endl;PRINT(y)/替换后:替换后:cout “a=”y endl;PRINT(x+y)/替换后:替换后:cout “a=”x+y endl;PRINT(1+2)/替换后:替换后:cout “a=”1+2 endl;print(x,y)/*替换后:替换后:cout “ab=”x*y endl;cout “ab=”x/y endl;*/print(2+6,4+7)/*替换后:替换后:cout “ab=”2+6*4+7 endl;cout “ab=”2+6/4+7 endl;*/运行:运行:请输入两个整数:请输入两个整数:8 5 a=8 a=5

49、a=13 a=3 a b=40a b=1 a b=33a b=1028第28页编译预处理编译预处理条件编译命令条件编译命令l使用宏名作为程序段是否被编译条件:使用宏名作为程序段是否被编译条件:格式格式1:#ifdef 宏名宏名 格式格式3:#ifndef 宏名宏名 程序段程序段 程序段程序段#endif#endif 格式格式2:#ifdef 宏名宏名 格式格式4:#ifndef 宏名宏名 程序段程序段1 程序段程序段1#else#else 程序段程序段2 程序段程序段2#endif#endif 作用:作用:通常源程序中全部语句都将被编译,但有时希望源程序中某个程序段只有在满通常源程序中全部语句

50、都将被编译,但有时希望源程序中某个程序段只有在满足某种条件时才被编译,而条件不满足时则不被编译,就好像该程序段从源程序中足某种条件时才被编译,而条件不满足时则不被编译,就好像该程序段从源程序中消失了一样,此时可选取上面格式之一来实现有条件编译。消失了一样,此时可选取上面格式之一来实现有条件编译。29第29页编译预处理编译预处理条件编译命令条件编译命令l几点说明:几点说明:以格式以格式1为例,当源程序中使用为例,当源程序中使用#ifdef 宏名宏名程序段程序段#endif 结构时,若该程序段结构时,若该程序段要被编译,可在该结构前面加上一条定义宏名预处理命令(要被编译,可在该结构前面加上一条定义

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 教育专区 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服