第5章-函数与预处理.ppt
第第5 5章章 函数与预处理函数与预处理 5.1 函数的定义函数的定义 5.2 函数的调用函数的调用 5.3 指针与函数指针与函数 5.4 函数的嵌套函数的嵌套 5.5 函数的递归函数的递归 5.6 内联函数和重载函数内联函数和重载函数 5.7 带默认形参值的函数带默认形参值的函数 5.8 作用域与生命期作用域与生命期 5.9 编译预处理编译预处理12/23/20221Question?什么是函数?什么是函数?为什么要使用函数?为什么要使用函数?12/23/202225.1 函数的定义函数的定义函数函数的概念的概念函数是一个能完成某一独立功能的程序函数是一个能完成某一独立功能的程序模块模块函数函数的作用的作用把一个复杂的程序分解成若干个功能相把一个复杂的程序分解成若干个功能相对独立的小模块对独立的小模块避免代码的重复,优化程序结构,提高避免代码的重复,优化程序结构,提高程序的开发效率程序的开发效率12/23/20223函数的定义函数的定义一般格式一般格式合法标识符合法标识符函数返回值类型函数返回值类型缺省缺省int型型无返回值无返回值void函数体函数体数据类型数据类型 函数名函数名(形式参数列表形式参数列表)说明部分说明部分语句部分语句部分例例 有参函数有参函数 int max(int x,int y)int z;z=xy?x:y;return(z);例例 有参函数有参函数 int max(int x,y)int z;z=xy?x:y;return(z);例例 空函数空函数 dummy()函数体为空函数体为空例例 无参函数无参函数 printstar()cout“*n”;或或 printstar(void)cout“*n”;12/23/20224函数的返回值函数的返回值返回语句返回语句形式:形式:return(表达式表达式);或或 return 表达式表达式;或或 return;功能:使程序控制从被调用函数返回到调用函数功能:使程序控制从被调用函数返回到调用函数中,同时把返中,同时把返回回值值(只能有一个)(只能有一个)带给调用函数带给调用函数说明:说明:u函数中可有多个函数中可有多个return语句语句,但每次调用只能执行一个但每次调用只能执行一个u若无若无return语句,遇语句,遇时,自动返回调用函数时,自动返回调用函数u若函数类型与若函数类型与return语句中表达式值的类型不一致,语句中表达式值的类型不一致,按前者为准,自动转换按前者为准,自动转换-函数调用转换函数调用转换uvoid型函数型函数可无可无return语句语句例例 无返回值函数无返回值函数 void swap(int x,int y)int temp;temp=x;x=y;y=temp;12/23/20225例例 函数返回值类型转换函数返回值类型转换#include max(float x,float y)float z;z=xy?x:y;return(z);void main()float a,b;int c;cinab;c=max(a,b);coutMax is c;12/23/20226函数声明函数声明函数声明也称为函数原型说明函数声明也称为函数原型说明u一般形式一般形式数据类型数据类型 函数名函数名(形参形参类型类型说明表说明表);例:例:double power(double,int);或或 数据类型数据类型 函数名函数名(形参列表形参列表);例:例:double power(double x,int n);12/23/20227函数声明说明函数声明说明函数原型说明中形参名可以任意;函数原型说明中形参名可以任意;除形参名外,函数原型必须和所定义的函除形参名外,函数原型必须和所定义的函数完全一致;数完全一致;函数调用在前,定义在后时,必须在调用函数调用在前,定义在后时,必须在调用该函数之间的位置对函数进行原型说明;该函数之间的位置对函数进行原型说明;当函数定义出现在函数调用之前时,可省当函数定义出现在函数调用之前时,可省略函数原型声明略函数原型声明main是主函数,在程序中不被任何函数调是主函数,在程序中不被任何函数调用,不需要原型说明。用,不需要原型说明。12/23/202285.2 函数的调用函数的调用函数的调用形式函数的调用形式u函数名函数名(实际参数表实际参数表);u说明:说明:l实参与形参实参与形参个数相等,类型一致,按个数相等,类型一致,按顺序一一对应顺序一一对应l实参可以是常量,变量,表达式,它实参可以是常量,变量,表达式,它们在们在调用前都应有确定的值调用前都应有确定的值l对于对于无参函数无参函数,函数调用中的实参表,函数调用中的实参表为空,但为空,但圆括号不能省略圆括号不能省略12/23/202295.2 函数的调用函数的调用调用方式调用方式u函数语句函数语句 例:例:printstar();cout“Hello,World!”;u函数表达式函数表达式 例:例:m=max(a,b)*2;u函数参数函数参数 例例 coutmax(a,b);m=max(a,max(b,c);12/23/2022105.2.3 函数调用的过程函数调用的过程main()调调fun()结束结束fun()返回返回保存:保存:返回地址返回地址当前现场当前现场恢复:恢复:主调程序现场主调程序现场返回地址返回地址12/23/2022115.2.4 参数传递机制参数传递机制C+中有两种不同的参数传递机制中有两种不同的参数传递机制u传值调用传值调用l变量的值传递变量的值传递l变量的地址值传递变量的地址值传递u引用调用引用调用12/23/202212传值调用传值调用在函数被调用时才分配形参的存储单元。在函数被调用时才分配形参的存储单元。实参可以是常量、变量或表达式。实参可以是常量、变量或表达式。实参类型必须与形参相符。实参类型必须与形参相符。传递时是传递参数值,即单向传递,形传递时是传递参数值,即单向传递,形参值的修改并不会影响实参的值。参值的修改并不会影响实参的值。12/23/202213传值调用示例传值调用示例XN被调函数:被调函数:主调函数:主调函数:3 2.5AD=power(A,3)2.53double power(double X,int N)12/23/202214例例5.9 输入两整数交换后输出输入两整数交换后输出(传递变量的值传递变量的值)#includeiostream.hvoid swap(int x,int y)int t=x;x=y;y=t;void main()int a=3;int b=4;couta=ab=bendl;cout-swap-endl;swap(a,b);couta=ab=bendl;34a:b:调用前:调用前:调用结束:调用结束:34a:b:调用:调用:34x:y:34a:b:swap:34a:b:43x:y:temp12/23/202215例例5.10 输入两整数交换后输出输入两整数交换后输出(传递变量的地址,交换变量的值传递变量的地址,交换变量的值)#includeiostream.hvoid swap(int*x,int*y)int t=*x;*x=*y;*y=t;void main()int a=3;int b=4;couta=ab=bendl;cout-swap-endl;swap(&a,&b);couta=ab=bendl;a34b调前:调前:a34b调调swap:x&a&bya43b交换:交换:x&a&bya43b返回:返回:12/23/202216例例5.11 输入两整数交换后输出输入两整数交换后输出(传递变量的地址,交换变量的地址传递变量的地址,交换变量的地址)#includeiostream.hvoid swap(int*x,int*y)int*t=x;x=y;y=t;void main()int a=3;int b=4;couta=ab=bendl;cout-swap-endl;swap(&a,&b);couta=ab=bendl;a34b调前:调前:a34b调调swap:x&a&bya34b交换:交换:y&a&bxa34b返回:返回:12/23/202217引用调用引用调用引用引用(&)是标识符的别名是标识符的别名,例如例如:int i,j;int&ri=i;/建立一个建立一个int型的引用型的引用ri,并将其并将其 /初始化为变量初始化为变量i的一个别名的一个别名j=10;ri=j;/相当于相当于 i=j;声明一个引用时,必须同时对它进行初始化,声明一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。使它指向一个已存在的对象。一旦一个引用被初始化后,就不能改为指向其一旦一个引用被初始化后,就不能改为指向其它对象。它对象。引用可以作为形参引用可以作为形参 void swap(int&a,int&b).12/23/202218例例5.13 输入两整数交换后输出输入两整数交换后输出(使用引用调用使用引用调用)#includeiostream.hvoid swap(int&x,int&y)int t=x;x=y;y=t;void main()int a=3;int b=4;couta=ab=bendl;cout-swap-endl;swap(a,b);couta=ab=bendl;a34b调前:调前:a34b调调swap:xa的别名的别名b的别名的别名ya43b返回:返回:a43b交换:交换:xa的别名的别名b的别名的别名y12/23/2022195.3 指针与函数指针与函数指针变量作为函数参数指针变量作为函数参数函数调用中数组的传递函数调用中数组的传递函数指针函数指针(指向函数的指针指向函数的指针)指针函数指针函数(函数返回值为指针函数返回值为指针)12/23/202220函数调用中数组的传递函数调用中数组的传递1.实参为数组名,形参为指针变量实参为数组名,形参为指针变量u例例5.14 用用sort函数对整型数组进行排序函数对整型数组进行排序void sort(int*s,int n)void main()int aN;sort(a,N);当数组首地址当数组首地址a传递传递给形参指针变量给形参指针变量s后,后,a和和s指向同一块内存指向同一块内存空间空间12/23/202221函数调用中数组的传递函数调用中数组的传递2.实参为数组名,形参也为数组名实参为数组名,形参也为数组名u例例5.16 用用inverse函数逆序输出整型数组函数逆序输出整型数组void inverse(int s,int n);void main()int tN;inverse(t,N);形参数组与实参数形参数组与实参数组指向同一块内存组指向同一块内存空间空间一维形参数组一维形参数组大小可不指定,大小可不指定,但多维形参数但多维形参数组仅可省略第组仅可省略第一维一维12/23/202222函数调用中数组的传递函数调用中数组的传递3.实参为数组名,形参为引用实参为数组名,形参为引用u例例5.19 用用inverse函数逆序输出整型数组函数逆序输出整型数组typedef int array10;void inverse(array&s,int n);void main()int tN;inverse(t,N);为数组为数组t起了个别名起了个别名s,对数组对数组s操作,就操作,就相当于对相当于对t操作操作定义一个长度为定义一个长度为10的整型数组,的整型数组,并将其作为一个并将其作为一个类型,类型名为类型,类型名为array12/23/202223函数指针函数指针(指向函数的指针指向函数的指针)函数在编译时被分配的函数在编译时被分配的入口地址入口地址,用用函数名函数名表示表示max.指令1指令2u函数指针变量赋值函数指针变量赋值:如如p=max;函数返回值的数据类型专门存放函数入口地址可指向返回值类型相同的不同函数函数指针:指向函数的指针变量,该指针存储的是函数指针:指向函数的指针变量,该指针存储的是函数的入口地址,它指向程序代码存储区。函数的入口地址,它指向程序代码存储区。u定义形式:定义形式:数据类型数据类型 (*指针变量名指针变量名)(形参列表形参列表);如如 int (*p)(int a,int b);函数指针变量指向的函数必须有函数说明u函数调用形式:函数调用形式:c=max(a,b);c=(*p)(a,b);c=p(a,b);u对函数指针变量对函数指针变量p n,p+,p-无意义无意义()不能省int(*p)()与 int *p()不同12/23/202224例例5.20 用函数指针变量调用函数用函数指针变量调用函数#includeiostream.hint func(int a,int b);void main()int(*pf)(int a,int b);pf=func;coutplease enter two integers:mn;int result=(*pf)(m,n);/int result=pf(m,n);coutresult isresultab;process(a,b,max);process(a,b,min);process(a,b,add);void process(int x,int y,int(*fun)()int result;result=(*fun)(x,y);coutresultendl;int max(int x,int y)coutcoutmax=;y?x:y);return(xy?x:y);int min(int x,int y)coutcoutmin=;min=;return(xy?x:y);return(xy?x:y);int add(int x,int y)coutcoutsum=;sum=;return(x+y);return(x+y);12/23/202226指针函数指针函数指针函数:函数的返回值为指针的函数指针函数:函数的返回值为指针的函数u定义形式:定义形式:数据类型数据类型 *函数名函数名(参数表参数表);如如 int *pf(int x,int y);例例5.22(p150)char*month_name(int n)char*name=“illegal month”,“January”,“December”;return(n12)?name0:namen);12/23/2022275.4 函数的嵌套调用函数的嵌套调用main调调fun1()结束结束fun1()调调fun2()返回返回fun2()返回返回12/23/202228例例5.23 用截弦法求解用截弦法求解f(x)=x34x2+9x16的根的根(2)连接连接f(x1)和和f(x2)两点,此线两点,此线(即弦即弦)交交x轴于轴于x,如右如右图图所示所示再从再从x求出求出f(x)。xyxf(x1)f(x)x1x2f(x2)x点坐标可用下式求出:点坐标可用下式求出:(1)取两个不同点取两个不同点x1、x2,如果如果f(x1)和和f(x2)符号相反,则符号相反,则(x1,x2)区间内必有区间内必有一个根。如果一个根。如果f(x1)与与f(x2)同符号,同符号,则应改变则应改变x1、x2,直到直到f(x1)、f(x2)异异号为止。注意号为止。注意x1、x2的值不应差太大,的值不应差太大,以保证以保证(x1,x2)区间只有一根。区间只有一根。12/23/202229根据上述思路画出根据上述思路画出n-s流程流程图,图,如右如右图图所示所示输入输入x1、x2,求求f(x1)、f(x2)直到直到f(x1)与与f(x2)异号异号求求f(x1)与与f(x2)连线与连线与x轴的轴的交点交点xy=f(x),y=f(x1)y与与y1同号同号x1=xy1=yx2=xy2=y直到直到|f(x)|root=x 输出输出root真真假假(3)若若f(x)与与f(x1)同符号,则根必在同符号,则根必在(x,x2)区间内,此时将区间内,此时将x作为新的作为新的x1。如果如果f(x)与与f(x2)同符号,则表示根在同符号,则表示根在(x1,x2)区间内,将区间内,将x作为新的作为新的x2.(4)重复步骤重复步骤(2)和和(3),直到,直到|f(x)|0)/f(x)与与f(x1)同符号同符号 y1=y;x1=x;else x2=x;while(fabs(y)=0.000001);return x;12/23/202232void main()/主函数主函数 double x1,x2,y1,y2,x;do cout请输入根所在的范围:请输入根所在的范围:x1x2;y1=f(x1);y2=f(x2);cout两端点的值为两端点的值为y1,y2=0);x=root(x1,x2);cout在在x1与与x2“之间,方程的解为之间,方程的解为x1)1.从数学上定义从数学上定义2.源程序源程序#includeiostream.h double fac(int n)double f;if(n=1)f=1;else f=n*fac(n-1);return f;12/23/202236void main()int a;double y;coutinput a integer number:a;y=fac(a);couta!=yendl;12/23/2022373.执行过程执行过程:设输入设输入n5fac(5)f=5 fac(4);fac(4)f=4 fac(3);return f;fac(3)f=3 fac(2);return f;fac=4!n=4n=3fac=3!12/23/2022383.执行过程执行过程:设输入设输入n5fac(2)f=2 fac(1);return f;fac(1)f=1;return f;n=1fac=1n=2fac=2!12/23/202239可简化表示为可简化表示为n=1n=2n=3n=4fac=4!fac=3!fac=2!fac=1n=5 当变成机器代码时当变成机器代码时,将其拉成直线将其拉成直线(线性程线性程序代码序代码)。12/23/202240猴子吃桃问题猴子吃桃问题猴子第一天摘下若干个桃子,当即吃了猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第剩下的一半零一个。到第1010天早上想再天早上想再吃时,见只剩一个桃子了。求第一天共吃时,见只剩一个桃子了。求第一天共摘了多少桃子。摘了多少桃子。12/23/202241#include using namespace std;all(int day)int sum;if(day=10)sum=1;else sum=2*(all(day+1)+1);return sum;void main()coutthe num is:endl;coutall(1)endl;12/23/202242例例 汉诺塔问题汉诺塔问题43有三根针有三根针A、B、C。A针上有针上有N个盘子,个盘子,大的在下,小的在上,要求把这大的在下,小的在上,要求把这N个盘子从个盘子从A针移到针移到C针,在移动过程中可以借助针,在移动过程中可以借助B针,每针,每次只允许移动一个盘,且在移动过程中在三次只允许移动一个盘,且在移动过程中在三根针上都保持大盘在下,小盘在上。根针上都保持大盘在下,小盘在上。ABC12/23/202243例:三个盘子例:三个盘子44ABC12/23/202244例:三个盘子例:三个盘子45ABC12/23/202245分析:分析:将将n 个盘子从个盘子从A针移到针移到C针可以分解为下面三个步骤针可以分解为下面三个步骤将将A 上上n-1个盘子移到个盘子移到 B针上(借助针上(借助C针)针);把把A针上剩下的一个盘子移到针上剩下的一个盘子移到C针上针上;将将n-1个盘子从个盘子从B针移到针移到C针上(借助针上(借助A针)针);事实上,上面三个步骤包含两种操作:事实上,上面三个步骤包含两种操作:将多个盘子从一个针移到另一个针上,这是一个递将多个盘子从一个针移到另一个针上,这是一个递归的过程。归的过程。hanoi函数实现。函数实现。将将1个盘子从一个针上移到另一针上。个盘子从一个针上移到另一针上。用用move函数实现。函数实现。12/23/202246#include using namespace std;void move(char getone,char putone)cout getone putoneendl;void hanoi(int n,char one,char two,char three)if(n=1)move(one,three);else hanoi(n-1,one,three,two);move(one,three);hanoi(n-1,two,one,three);12/23/202247void main()int m;coutm;coutthe steps to moving m diskes:CA-BC-BA-CB-AB-CA-C12/23/2022485.6 内联函数和重载函数内联函数和重载函数内联函数的引入:内联函数的引入:1.1.函数调用会降低效率函数调用会降低效率 2.2.调用内联函数是将程序中出现的内联调用内联函数是将程序中出现的内联函数的调用表达式用该内联函数的函数体函数的调用表达式用该内联函数的函数体进行替换,虽然增加代码量,但不用进行替换,虽然增加代码量,但不用“保保留现场留现场”,效率比一般函数高。,效率比一般函数高。12/23/202249内联函数声明与使用内联函数声明与使用声明时使用关键字声明时使用关键字 inline。编译时在调用处用函数体进行替换编译时在调用处用函数体进行替换,节省了参节省了参数传递、控制转移等开销。数传递、控制转移等开销。注意:注意:u内联函数的声明必须出现在内联函数第一次被调内联函数的声明必须出现在内联函数第一次被调用之前;用之前;u内联函数体内不能有内联函数体内不能有循环语句循环语句和和switch语句;语句;u递归函数不能被用做内联函数;递归函数不能被用做内联函数;u内联函数的函数体不宜过大,以内联函数的函数体不宜过大,以1-5行为宜;行为宜;12/23/202250例例 内联函数应用举例内联函数应用举例#includeinline double CalArea(double radius)return 3.14*radius*radius;int main()double r(3.0);double area;area=CalArea(r);coutareaendl;return 0;12/23/202251重载函数的声明重载函数的声明C+允许功能相近的函数在允许功能相近的函数在相同的作用域相同的作用域内以内以相同函数名相同函数名声明,从而形成重载。声明,从而形成重载。方便使用,便于记忆。方便使用,便于记忆。例:例:形参类型形参类型不同不同int add(int x,int y);float add(float x,float y);形参个数形参个数不同不同int add(int x,int y);int add(int x,int y,int z);12/23/202252注意事项注意事项不要将不同功能的函数声明为重载函数,以免出不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。这样不好:现调用结果的误解、混淆。这样不好: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)return x+y;float add(float x,float y)return x-y;重载函数的形参必须不同重载函数的形参必须不同:个数个数不同或不同或类型类型不同。不同。编译程序将根据实参和形参的类型及个数的最佳编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。匹配来选择调用哪一个函数。12/23/202253例例5.28 编程求两个或三个操作数之和编程求两个或三个操作数之和#includeiostream.hint sum(int,int);int sum(int,int,int);double sum(double,double);double sum(double,double,double);void main()coutsum(2,5)endl;coutsum(2,5,7)endl;coutsum(1.2,5.0,7.5)b;if(b0)int c;.c的作用域b的作用域12/23/202262函数作用域函数作用域具有函数作用域的标识符在该函数内任何地方可具有函数作用域的标识符在该函数内任何地方可见见在在C+中,只有中,只有goto语句的标号具有函数作用域语句的标号具有函数作用域u声明形式声明形式 标号:语句标号:语句u示例示例void f()goto A;int b;cinb if(b0)A:;goto B;B:cout“All done”M12/23/202264文件作用域文件作用域不在前述各个作用域中出现的声明,具有不在前述各个作用域中出现的声明,具有文件作用域,这样声明的标识符的作用域文件作用域,这样声明的标识符的作用域开始于声明点,结束于文件尾。开始于声明点,结束于文件尾。12/23/202265可见性可见性可见性是从对标识符的引用的角度来谈可见性是从对标识符的引用的角度来谈的概念的概念可见性表示从内层作用域向外层作用域可见性表示从内层作用域向外层作用域“看看”时能看见什么。时能看见什么。如果标识在某处可见,则就可以在该处如果标识在某处可见,则就可以在该处引用此标识符。引用此标识符。块作用域块作用域类作用域类作用域文件作用域文件作用域12/23/202266可见性可见性标识符应声明在先,引用在后。标识符应声明在先,引用在后。如果某个标识符在外层中声明,且在内如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识层中没有同一标识符的声明,则该标识符在内层可见。符在内层可见。对于两个嵌套的作用域,如果在内层作对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不识符,则外层作用域的标识符在内层不可见可见。12/23/202267全局变量和局部变量全局变量和局部变量局部变量局部变量umain函数内部声明的也是局部变量函数内部声明的也是局部变量u不同函数中的同名局部变量没有任何关系不同函数中的同名局部变量没有任何关系全局变量全局变量u是在文件作用域中声明的变量是在文件作用域中声明的变量u作用域从声明的位置开始到程序结束作用域从声明的位置开始到程序结束12/23/202268例例5.29 文件作用域及作用域运算符文件作用域及作用域运算符#includeiostream.hint i;void main()i=5;int i=7;couti=i;couti=:i;couti=i;可以在块作用域中可以在块作用域中存取被屏蔽的文件存取被屏蔽的文件作用域中的标识符作用域中的标识符12/23/202269#includeiostream.hint i;void prt()for(i=0;i5;i+)cout*;coutendl;void main()for(i=0;i5;i+)prt();例例 外部变量副作用外部变量副作用运行结果:运行结果:*12/23/202270生命期生命期程序中的各种变量在创建和删除之间所经程序中的各种变量在创建和删除之间所经过的时间被称为生命期。过的时间被称为生命期。12/23/202271静态生存期静态生存期这种生存期与程序的运行期相同。这种生存期与程序的运行期相同。在文件作用域中声明的对象具有这在文件作用域中声明的对象具有这种生存期。种生存期。在函数内部声明静态生存期对象,在函数内部声明静态生存期对象,要冠以关键字要冠以关键字static12/23/202272示例示例#includeint i=5;/文件作用域文件作用域int main()couti=iendl;return 0;i具有静态生存期具有静态生存期12/23/202273动态生存期动态生存期块作用域中声明的,没有用块作用域中声明的,没有用static修饰的修饰的对象是动态生存期的对象(习惯称局部生对象是动态生存期的对象(习惯称局部生存期对象)。存期对象)。开始于程序执行到声明点时,结束于命开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。名该标识符的作用域结束处。12/23/202274示例示例#includevoid fun();void main()fun();fun();void fun()static int a=1;int i=5;a+;i+;couti=i,a=aendl;运行结果:运行结果:i=6,a=2i=6,a=3i是动态生存期是动态生存期a是静态生存期是静态生存期12/23/202275例例 变量的生存期与可见性变量的生存期与可见性#includeint i=1;/i 为全局变量,具有静态生存期。为全局变量,具有静态生存期。void main(void)static int a;/静态局部变量,有全局寿命,局部可见。静态局部变量,有全局寿命,局部可见。int b=-10;/b,c为局部变量,具有动态生存期。为局部变量,具有动态生存期。int c=0;void other(void);cout-MAIN-n;cout i:i a:a b:b c:cendl;c=c+8;other();cout-MAIN-n;cout i:i a:a b:b c:cendl;i=i+10;other();12/23/202276void other(void)static int a=2;static int b;/a,b为静态局部变量,具有全局寿命,局部可见。为静态局部变量,具有全局寿命,局部可见。/只第一次进入函数时被初始化。只第一次进入函数时被初始化。int c=10;/C为局部变量,具有动态生存期,为局部变量,具有动态生存期,/每次进入函数时都初始化。每次进入函数时都初始化。a=a+2;i=i+32;c=c+5;cout-OTHER-n;cout i:i a:a b:b c:cendl;b=a;12/23/202277运行结果:运行结果:-MAIN-i:1 a:0 b:-10 c:0-OTHER-i:33 a:4 b:0 c:15-MAIN-i:33 a:0 b:-10 c:8-OTHER-i:75 a:6 b:4 c:1512/23/2022785.9 编译预处理编译预处理C+提供有以下编译预处理指令提供有以下编译预处理指令u文件包含文件包含u宏定义宏定义u条件编译条件编译12/23/202279文件包含文件包含#include 包含指令包含指令u将一个源文件嵌入到当前源文件中该点将一个源文件嵌入到当前源文件中该点处。处。u#include l按标准方式搜索,文件位于按标准方式搜索,文件位于C+系统系统目录的目录的include子目录下子目录下u#include文件名文件名l首先在当前目录中搜索,若没有,再首先在当前目录中搜索,若没有,再按标准方式搜索。按标准方式搜索。12/23/202280文件包含应用举例文件包含应用举例文件文件test.cpp#include#include add.h/是否可使用是否可使用void main()int a,b;a=5;b=7;/可在一行写几个语句可在一行写几个语句 int c=add(a,b);couta+b=cendl;/也可将一个语句写在多行上也可将一个语句写在多行上文件文件add.hint add(int x,int y)int z=x+y;return z;12/23/202281宏定义宏定义#define 宏定义指令宏定义指令u定义符号常量,很多情况下已被定义符号常量,很多情况下已被const定义语句定义语句取代。取代。l例:例:#define PI 3.1415926u定义带参数宏,已被定义带参数宏,已被内联函数内联函数取代。取代。l例:例:#define X(A,B)A*B*B#undefu删除由删除由#define定义的宏,使之不再起作用。定义的宏,使之不再起作用。l例:例:#undef PI宏定义不是宏定义不是C+语句,而是发布给编译系统的预处理命语句,而是发布给编译系统的预处理命令,使得在编译程序前,将程序中所有出现宏名的地方令,使得在编译程序前,将程序中所有出现宏名的地方都用宏体进行替换,并将形参替换为实参都用宏体进行替换,并将形参替换为实参行末不能加行末不能加分号,否则分号,否则会被当成字会被当成字符串的一部符串的一部分一起替换分一起替换12/23/202282条件编译条件编译#if 和和#endif#if 常量表达式常量表达式 /当当“常量表达式常量表达式”非零时编译非零时编译 程序正文程序正文#endif .12/23/202283条件编译条件编译#if#else#endif#if 常量表达式常量表达式 /当当“常量表达式常量表达式”非零时编译非零时编译 程序正文程序正文1#else /当当“常量表达式常量表达式”为零时编译为零时编译 程序正文程序正文2#endif12/23/202284条件编译条件编译#if#elif#else#endif#if 常量表达式常量表达式1 程序正文程序正文1 /当当“常量表达式常量表达式1”非零时编译非零时编译#elif 常量表达式常量表达式2 程序正文程序正文2 /当当“常量表达式常量表达式2”非零时编译非零时编译#else 程序正文程序正文3 /其它情况下编译其它情况下编译#endif12/23/202285条件编译条件编译#ifdef#endif#ifdef 标识符标识符 程序段程序段1#else 程序段程序段2#endif 如果如果“标识符标识符”经经#defined定义过,且未定义过,且未经经undef删除,则编译程序段删除,则编译程序段1,否则编译,否则编译程序段程序段2。12/23/202286条件编译条件编译#ifndef#endif#ifndef 标识符标识符 程序段程序段1#else 程序段程序段2#endif 如果如果“标识符标识符”未被定义过,则编译程序未被定义过,则编译程序段段1,否则编译程序段,否则编译程序段2。12/23/202287多文件结构(例多文件结构(例5-40)一个源程序可以划分为多个源文件:一个源程序可以划分为多个源文件:u类声明文件(类声明文件(.h文件)文件)u类实现文件(类实现文件(.cpp文件)文件)u类的使用文件(类的使用文件(main()所在的所在的.cpp文件文件)利用工程来组合各个文件。利用工程来组合各个文件。12/23/202288编程实现以下功能编程实现以下功能主界面:主界面:*学生学号管理系统学生学号管理系统*1、增加学号、增加学号 2、删除学号、删除学号 3、修改学号、修改学号 4、查询学号、查询学号 5、插入学号、插入学号 6、学号排序、学号排序 7、显示所有学号、显示所有学号 0、退出系统、退出系统 请选择相应的功能(输入功能前面的序号):请选择相应的功能(输入功能前面的序号):12/23/202289编程实现以下功能编程实现以下功能1、增加学号、增加学号l提示输入一个学号,并将其排在已有学号的后面提示输入一个学号,并将其排在已有学号的后面2、删除学号、删除学号l提示输入一个学号,并将其从已有学号中删除提示输入一个学号,并将其从已有学号中删除 3、修改学号、修改