四讲函数及变量的作用域.ppt

上传人:sccc 文档编号:5381770 上传时间:2023-07-01 格式:PPT 页数:64 大小:781.51KB
返回 下载 相关 举报
四讲函数及变量的作用域.ppt_第1页
第1页 / 共64页
四讲函数及变量的作用域.ppt_第2页
第2页 / 共64页
四讲函数及变量的作用域.ppt_第3页
第3页 / 共64页
四讲函数及变量的作用域.ppt_第4页
第4页 / 共64页
四讲函数及变量的作用域.ppt_第5页
第5页 / 共64页
点击查看更多>>
资源描述

《四讲函数及变量的作用域.ppt》由会员分享,可在线阅读,更多相关《四讲函数及变量的作用域.ppt(64页珍藏版)》请在三一办公上搜索。

1、第四讲函数及变量的作用域,函数的定义和说明函数的调用函数的参数内联函数函数重载函数的嵌套调用和递归调用作用域C+的系统函数,主要内容,4.1 函数的定义和说明,函数的定义格式函数的说明方法,一个C+函数由函数头与函数体两部分组成。形式如下:函数类型 函数名(形式参数类型 形式参数名,)函数体 如:int fun1(char c,float f)int m=1;m+=c+f;return m;,函数的定义格式,即函数返回值的类型。无返回值为void类型,语句序列。描述了实现功能的过程,并一般要最后执行一条return语句。,可包含多个形式参数。定义了函数将从调用函数中接收多少个数据及其类型,返回

2、语句的形式为:return 表达式;这时表达式的结果就是函数的返回值,也称函数值。即返回的不是函数本身,而是一个值。若函数所执行的功能不需要返回数据,则可缺省 return语句。如:void spc(int n)for(int I=0;In;I+)cout*;注意:函数类型为void,若无默认为int。C+不允许函数定义嵌套。,函数的说明方法,其形式为:函数类型函数名(参数类型表);如:int absolute_value(int,double);要求在调用函数前让编译器知道其函数原型,以便编译器利用函数原型提供的信息来检查调用的合法性,强制参数为适当类型,保证参数的正确传递。而编译器获得函数

3、原型有两种情况:()当函数定义在调用之前时,则从定义中抽取函数原型。()当函数定义在调用之后时,则程序员须在调用之前用函数原型对函数进行声明,让编译器获得函数原型。,即所有参数的数据类型,对于标准库函数的函数原型都在头文件中提供了,程序可用#include命令包含进来即可;注意:函数原型和函数定义在返回类型、函数名和参数表上必须完全一致,否则编译错误。,注 意,#include void f1();/函数说明void f2();void main()f1();/函数调用 f2();void f1()/函数定义 cout Function f1.n;f2();void f2()cout Func

4、tion f2.n;,main(),f1(),f2(),4.2 函数的调用,函数的值和类型函数的传值调用函数的引用调用,函数的值和类型,函数调用通过调用表达式进行。表达式形式为:函数名(实参表列)函数调用过程是:为形参及函数体中的变量分配存储空间;用实参向形参传递数据;中断现行(调用)函数,将控制转交给被调用函数执行。函数调用后的返回过程是:先计算出返回语句中的值若表达式值的类型与函数类型不一致,则强制转换。将计算出的表达式值返回给调用函数作为返回值。将控制由被调用函数转向调用函数,执行后面的语句。,如:#include int lmax(int,int);/函数声明 void main()i

5、nt limit=32;char ch=A;long mval;mval=lmax(limit,ch);/调用表达式 coutb?a:b);,实参的个数、类型及顺序要与形参保持一致,形式参数,实际参数,说明:(1)实参在进行函数调用时,必须具有确定的值,以便把这些值传送给形参。(2)形参变量只有在被调用时,才分配内存单元;调用结束时,即刻释放所分配的内存单元。因此,形参只有在该函数内有效。调用结束,返回调用函数后,则不能再使用该形参变量。(3)实参对形参的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。(4)实参和形参占用不同的内存单元,即使同名也互不影响。,函

6、数的传值调用,C+中变量值有两种:变量本身值和变量地址值。而形参的类型也就分为两种:一般类型和指针类型。则传值调用的方式也有两种:传值调用和传址调用有时也称:直接调用与间接调用,1、传值调用的实现机制和特点,实现机制是:调用函数中的数据只是在调用之初通过实参向形参传递,之后各占有不同的空间,并且不再发生联系,互不干扰。特点是:形参值的改变不影响实参。实参本身的值在调用前后和调用过程中都不发生变化。,函数swap本想实现交换a和b值的功能,但调用结果却不如意。原因就在于这种调用是一种值调用。例:#include void swap(int,int);void main()int a=3,b=5;

7、coutbefore swap:a=a,b=bendl;swap(a,b);coutafter swap:a=a,b=bendl;void swap(int a,int b)int temp;temp=a;a=b;b=temp;coutin swap:a=a,b=bendl;,调用swap时,内存单元分配情况:,3,5,3,temp=a;a=b;b=temp;,实现机制是:实参为某变量地址值,形参为指针类型。在调用时,将地址值赋给形参,使形参指针指向该变量。则以后可直接通过形参指针来访问该变量。特点是:可通过改变形参所指向的变量值来影响实参所对应的变量值。,2、传址调用的实现机制和特点,函数s

8、wap实现了交换a和b值的功能。原因就在于这种调用是一种传址调用。例:#include void swap(int*,int*);void main()int a=3,b=5;coutbefore swap:a=a,b=bendl;swap(,调用swap时,内存单元分配情况:,3,5,3,temp=*a;*a=*b;*b=temp;,函数的引用调用,使用引用作为函数形参时,调用函数的实参要用变量名。将实参变量名赋给形参的引用,则在被调函数中,对引用的操作,实质就是直接通过引用来操作实参的变量值。显然,引用传递方式具有传址调用的效果,又有传值调用的语法简单性和可读性。注意:若只从调用语句观察,

9、是无法区别采用的是传值调用还是引用调用。,函数swap实现了交换a和b值的功能。这里调用是采用了引用调用。例:#include void swap(int,调用swap时,内存单元分配情况:,3,5,3,temp=a;a=b;b=temp;,4.3 函数的参数,函数参数的求值顺序设置函数参数的默认值使用数组作函数参数,函数参数的求值顺序,由于使用不同求值顺序的编译器而造成二义性。#include int add(int x,int y);/函数声明 void main()int a=4,b=6;int z=add(+a,a+b);/从左至右为5 11 coutzendl;/从右至左为5 10

10、int add(int x,int y)/函数定义(实现)return x+y;,设置函数参数的默认值,在函数说明语句中预先初始化一些参数的值,从而使调用语句中相应的参数可以缺省。如:int max(int,int,int=-32768);则在函数调用时可以不给最后一个参数传递值,而采用缺省值。如:max(i1,i2);/参数缺省调用 max(i1,i2,i3);/正常调用允许函数默认参数值,是为了让编程简单。设置函数参数的默认值是按从右至左的方式当又有声明又有定义时,定义中不允许默认参数。若只有定义,则默认参数才可出现在函数定义中。,注意:若一个函数中有多个默认参数,则参数缺省按从后向前的顺

11、序进行,如:void fun(int a=3,int,char c=a);/error 当调用函数时,也只能从右向左匹配参数。如:声明函数为:void func(int a,int b=2,int c=3,int d=5);则调用方法:func(2,15,3);/error,使用数组作函数参数,1、形参和实参都用数组 这种调用的机制是:形参和实参共用内存中的同一个数组空间。因此,在被调用函数中改变了数组中某个元素的值,对调用函数该数组的该元素值也被改变,因为是共用同一个数组。#include int a8=1,3,5,7,9,11,13;void fun(int b,int n)for(int

12、 I=0;In-1;I+)b7+=bI;void main()int m=8;fun(a,m);couta7endl;,#include void invert(char b,int n);void main()char s60;int n;couts;cout字符串原始顺序:sendl;n=strlen(s);invert(s,n);cout字符串反转后的顺序:sendl;void invert(char b,int n)for(int i=0;in/2;i+)char c=bi;bi=bn-1-i;bn-1-i=c;,输入一字符串个数,反序存放并输出,不能写成invert(sn,n),有问

13、题吗?,2、形参和实参都用对应数组的指针实际,也可一个使用指针,另一个使用数组。在使用指针时,可以直接用数组名,也可用另外定义的指向数组的指针。#include int a8=1,3,5,7,9,11,13;void fun(int*pa,int n)/函数声明与定义 for(int I=0;In-1;I+)*(pa+7)+=*(pa+I);void main()int m=8;fun(a,m);couta7endl;,#include void invert(char*b,int n);void main()char s60;int n;/char*p=s;couts;cout字符串原始顺序

14、:sendl;n=strlen(s);invert(s,n);/invert(p,n);cout字符串反转后的顺序:sendl;void invert(char*b,int n)for(int i=0;in/2;i+)char c=*(b+i);*(b+i)=*(b+n-1-i);*(b+n-1-i)=c;,输入一字符串个数,反序存放并输出,3、形参用引用实参用数组名其中要先用类型定义语句定义一个int型的数组类型。typedef int aref8;/类型定义int a8=1,3,5,7,9,11,13;void fun(aref,#include typedef char arr60;/先

15、用类型定义一个char型的数组类型void invert(arr,输入一字符串个数,反序存放并输出,4.4 内联函数,引入的原因定义方法注意事项,引入原因,目的是为了解决程序中函数调用的效率问题。函数调用时需要建立栈内存环境,进行参数传递,并产生程序执行转移,则都要有时间和空间的代价。而有时一些函数代码很短(行),却有高使用频率,造成处理现场的开销巨增。这时若将函数体嵌入函数调用处,则可避免每次调用函数的开销。大大提高效率。,通过将该函数声明为inline来实现。即在函数声明和定义中用inline来修饰。如:inline int isnumber(char);void main()char c

16、h;for(int I=1;Ich;int p=isnumber(ch);cout=0 编译器在看到inline后,为该函数创建一段代码,以便以后每次碰到该函数的调用都用相应代码来替代。,定义方法,注意事项,内联函数可以在一开始仅声明一次,但必须在被调用之前声明或定义为inline。因为内联函数的代码必须在被替换前生成被替换的代码。否则编译器同一般函数对待,产生函数调用。内联函数还有限制:函数内不能含有循环结构或switch结构;不能含有任何静态数据及数组声明。不能是递归函数。,注 意,4.5 函数重载,引入原因重载方式注意事项,引入原因,重载指用同一个函数名对应着多个函数实现的情况。如:求两

17、个数的较大值,若数的类型不同,则返回值类型不同。int max(int,int);float c=max(3.14,3.5);/error因此一个定义了实现整型数比较功能的函数无法用于实现实型数的比较,尽管其功能一致。这时就可采用重载。,在C+中,允许两个或两个以上的函数采用相同的名字,只要使用不同类型、不同数目的参数或不同的返回值,编译器便知道在什么情况下该调用哪个函数,这就叫函数重载。如:int max(int x,int y)return(xy)?x:y);double max(double x,double y)return(xy)?x:y);#include void main()c

18、outmax(10,20)endl;coutmax(1.23,2.34)endl;,重载方式,靠将实参的个数及类型和所被调用的f()函数的形参的个数及类型一一比较来判断。,()作为重载函数至少在参数个数、参数类型上有所不同。若仅在返回类型上不同,编译器是无法区别的。如:void func(int);int func(int);/错误 int min(int,int);int min(int,int,int);/正确 int add(int,int);double add(double,double);/正确()typedef定义的类型只是给已有类型取另外一个名字,编译器不能将其同原类型区分。如

19、:typedef INT int;void func(int x).void func(INT x)(3)重载函数一般应具有相同的功能,否则会破坏程序的可读性。,注意事项,4.6 函数的嵌套调用和递归调用,嵌套调用递归调用,嵌套调用,函数的嵌套调用是指在执行被调用函数时,被调用函数又调用了其它函数。其关系可表示如图所示:,例4.15 计算s=1k+2k+3k+N k#include const int k=4;const int n=6;/符号常量定义int power(int,int);/求幂的函数说明int sum(int,int);/求和的函数说明void main()coutSum o

20、f 1k+2k+3k+N k=;coutsum(k,n)endl;/调用sum函数,int sum(int k,int n)/*计算1到n的k次方之累加和*/int s=0;for(int i=1;i=n;i+)s+=power(i,k);/累加 return s;/调用f1函数 int power(int m,int n)/*计算m的n次方*/int p=1,i;for(i=1;in;i+)p*=m;/累乘算法 return p;,递归调用,函数的递归调用是指,一个函数在它的函数体内,直接或间接地调用它自身。如:求n!的程序 long fac(int n)if(n=1)return 1;el

21、se return fac(n-1)*n;/出现函数自调用注意两个递归条件:(1)初始条件:n=1时,n!=1(2)递归公式:n1时,n!=n*(n-1)!,三、调用函数本身,但参数值趋于结束条件,一、有一个使递归结束的条件,二、当条件成立时,不再调用自己,而有确定值,fac:=6,fac:=2,fac:=1,4.7 作用域,标识符的作用域规则作用域的种类局部变量和全局变量,标识符的作用域规则,规则为:标识符只能在说明它或定义它的范围内是可见的,而在该范围之外是不可见的。说明有:1、大多数标识符的说明与定义是一致的,只有少数例外。如:函数等。2、范围有大有小。最大为整个程序,最小为块,中间有文

22、件和函数。,作用域的种类,不同的标识符定义在不同的范围内有不同的作用域。按作用域的大小可分为:程序级:包含着组成该程序的所有文件。文件级:仅在定义它的文件内。函数级:在它所定义的函数体内。块级:定义在分程序中、语句块内。注意:作用范围一般是从定义时开始,到相应范围结束为止。,如:#include void main()int x(3),y(5);/double x(3.5);error for(;x0;x-)int x(4);coutxtyt;coutendlxtyendl;,在不同作用域中允许同名。,在同一作用域中不允许同名。,蓝色为函数作用域,绿色为块作用域,不为x的原因是局部优先,4 5

23、 4 5 4 505,局部变量和全局变量,1、局部变量是指作用域在函数级和块级的变量。2、全局变量是指作用域在程序级和文件级的变量。,#includeint i(5);/外部变量externstatic int j(6);/外部静态变量void min(int x,int y)/形参 int i(3);/自动变量 auto register int j(2);/寄存器变量 static int k(1);/内部静态变量 void main(),局部变量,全局变量,蓝色为文件作用域,绿色为函数作用域,注意:同名时是局部优先,分析程序结果,int a(5),b(7),c(10);coutatbtc

24、endl;coutatbtcendl;int b(8);double c(8.8);coutatbtcendl;a=b;int c;c=b;coutatbtcendl;coutatbtcendl;coutatbtcendl;,5 7 10,5 8 8.8,8 8 8,8 7 10,8 8 8.8,4.8 C+的系统函数,概述,C+系统将所提供的系统函数的说明分类放在不同的.h文件(头文件)中。如:数学处理函数(math.h)、字符串处理函数(string.h)、屏幕处理函数(conio.h)、图形处理函数(graph.h)。conconsole,控制台、安慰 具体使用需要看所用的C+版本的帮助

25、。注意:1、了解系统中有哪些系统函数。2、了解函数位于哪个头文件中。3、调用一个函数,须了解函数功能、参数和返回值。,如:#include#includevoid main()double I(30*3.1415/180);double x=sin(I);double y=cos(I);coutxyendl;,输入15个数,用函数求和与平均值,void main()double a15,s(0),ave(0);for(int i=0;iai;for(i=0;i15;i+)s+=ai;ave=s/15;cout和:sendl;cout平均值:aveendl;,sum(15),ave(15),do

26、uble sum(int x);/函数声明double ave(int x);/函数声明double a15,s(0);/全局变量void main()for(int i=0;iai;cout和:sum(15)endl;/函数调用 cout平均值:ave(15)endl;,double sum(int x)/求和函数的定义 for(i=0;ix;i+)s+=ai;return s;double ave(int x)/求平均值函数的定义 return s/x;,数组排序冒泡法,第一轮 B D C A E,原数据 B E D C A,第三轮 B A C D E,第二轮 B C A D E,第四轮

27、A B C D E,4 3 2 1,结论:轮数(外循环)为:n-1,每轮次数(内循环)为:n-i,void main()const int N=6;int bN=89,3,56,44,12,99;for(int i=1;ibj+1)/如果交换两数 int t=bj;bj=bj+1;bj+1=t;/输出排序后数组 for(int k=0;kN;k+)coutbkt;,int a10=8,5,7,8,3,5,6,1,9,1,n=10;for(i=0;i10;i+)for(j=i+1;j10;j+)if(ai=aj)aj=a-n;j-;/若相等,则用最后一个元素替代该数,个数相应减1,最后的元素去掉

28、同时本趟还要继续比较,long m;int flag;cinm;/输入int sqrtm=sqrt(m);for(int I=2;I=sqrtm;I+)if(m%I=0)/若能被某数整除 flag=0;/标志置0,并终止循环 break;else/否则标志置1,flag=1;if(flag)/如果全部比较后标志为1则是素数coutm is prime.n;else coutm isnt prime.n;,判断一个数是否素数?,int a10=8,5,7,8,3,5,6,1,9,1,b10,n=10;int i,j,flag,k=0;for(i=0;in;i+)flag=0;/用标志可简化编程

29、for(j=i+1;jn;j+)if(ai=aj)/若元素重复 flag=0;break;/置标志为0,并终止比较 elseflag=1;if(flag)/若比较一轮无重复 bk=ai,k+;/把此元素放入b/并使个数加1,输入10个数,去除重复值后排序,本讲作业,1、编程求出50至100之内所有素数之和(计算素数要求调用函数实现);2、设定数组的10个元素(有重复)并输出,调用函数(数组名作参数)去除数组重复值,再调用函数(数组名作参数)对无重复元素的数组排序,输出排序后的各元素;3、用函数重载的方式实现两个数的四则运算;4、看完吕凤翥书的P114至P123;5、教材P44第3题;6、看完教材第二章的内容!,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 建筑/施工/环境 > 农业报告


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号