第5章函数2内容提要•函数定义、函数调用、函数原型、函数返回值–难点:函数的参数传递与返回值•全局变量、自动变量、静态变量、寄存器变量–难点:变量的作用域与存储类型3引子—为什么用函数?2/)(bamain(){inta=2,intb=3;floatave;ave=(a+b)/2.0;printf(Average:%f”,ave);}main(){inta=2,intb=3;floatpow;pow=2*2*2;printf(“power:%f,pow);}ba422/)(2/)(2/)(2/)(dcbadcbamain(){inta=2,b=3,c=4,d=5;floatave1,ave2,ave;ave1=(a+b)/2.0;ave2=(c+d)/2.0;ave=(ave1+ave2)/2.0;printf(Average:%f”,ave);}include“math.h”main(){inta=2;intb=3;floatpow;pow1=pow(a,b);pow2=pow(c,d);printf(“power:%f,pow);}cdba如果求更多的数的平均值,是不是有些麻烦呢?那么求ab,cd,…,多个又是怎么做更简单的呢?是不是求45,也要自己写4*4*4*4*4呢?用到了库函数pow(x,y),用来计算xy,使程序简单,明了.定义在math.h中.类似的,求平均值,能不能也用一个函数表示.main(){inta=2,b=3,c=4,d=5;floatave1,ave2,ave;ave1=average(a,b);ave2=average(c,d);ave=average(ave1,ave2);printf(Average:%f”,ave);}库函数是有限的,不可能面面俱到,没有求平均值的库函数,怎么办?我们可以把求平均数编写成自定义函数.5#includestdio.hfloataverage(intx,inty){floatresult;result=(x+y)/2;returnresult;}main(){inta=2,b=3,c=4,d=5;floatave1,ave2,ave;ave1=average(a,b);ave2=average(c,d);ave=average(ave1,ave2);printf(Average:%f”,ave);}较大的程序一般分为若干个程序模块。C语言的基础是函数,可由主函数和若干个函数组成。将一些常用的功能模块编写成函数,供公共调用,可减少重复编写程序的工作量。本章的主要内容就是学习如何定义自定义函数,如何使用.6函数定义(definition)•一般形式:返回值类型函数名(类型参数1,类型参数2,……){函数体return表达式;}•如果没有参数,则应该用void注明•返回值类型与return语句配合–如果不需要返回值,则应该用void定义返回值类型,同时return语句之后不再需要任何表达式•当函数执行到return语句时,就中止函数的执行,返回到调用它的地方.教材164页7例5.1a计算两个整数的平均数教材165页/*函数功能:计算平均数函数入口参数:整型x,存储第一个运算数整型y,存储第二个运算数函数返回值:平均数*/intAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}8函数调用•函数调用一般格式:函数名(实参表列)•单向值传递•调用函数时,必须提供所有的参数•提供的参数个数、类型、顺序应与定义时相同9函数调用•有返回值时–放到一个数值表达式中,如c=max(a,b);–作为另一个函数调用的参数,如c=max(max(a,b),c);printf(%d\n,max(a,b));•无返回值时–函数调用表达式,如display(a,b);10例5.1b使用了Average函数的main()main(){inta=12;intb=24;intave;ave=Average(a,b);printf(Averageof%dand%dis%d.\n,a,b,ave);}教材165-167页11函数的参数和函数的值•形式参数(形参)在定义函数时函数名后面括弧中的变量名•必须指定形参的类型•实际参数(实参)在主调函数中调用一个函数时,被调函数的函数名后面括弧中的参数(可以是一个表达式)•实参可以是常量、变量或表达式12函数间的参数传递•形参和实参在内存中占用不同的内存单元•当主调函数调用被调函数时发生数据的传递,•只由实参传递给形参,且传递的是参数的值,即单向传递•实参类型必须与形参相符•在函数被调用时才分配形参的存储单元。13函数间的参数传递图示main(){inta=12;intb=24;intave;ave=Average(a,b);printf(Averageof%dand%dis%d.\n,a,b,ave);}教材165-167页intAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}main(){inta=12;intb=24;intave;ave=Average(a,b);printf(……);}数据传递执行顺序14函数的定义与使用小结•函数定义:被调函数必须是存在的函数(库函数或自定义函数)•函数声明:(也称函数原型)在主调函数中,对被调函数进行声明格式:返回值类型标识符被调用函数名(含类型说明的形参表)•函数调用一般格式:函数名(实参表列)教材167页15例5.1#includestdio.h/*函数功能:计算平均数函数入口参数:整型x,存储第一个运算数整型y,存储第二个运算数函数返回值:平均数*/intAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}main(){inta=12;intb=24;intave=Average(a,b);printf(Averageof%dand%dis%d.\n,a,b,ave);}教材167页哪些是形参?哪些是实参?那个语句返回值?返回谁的值?返回给谁?16例5.1#includestdio.hintAverage(intx,inty);/*声明Average()函数*/main(){inta=12;intb=24;intave=Average(a,b);printf(Averageof%dand%dis%d.\n,a,b,ave);}/*函数功能:计算平均数函数入口参数:整型x,存储第一个运算数整型y,存储第二个运算数函数返回值:平均数*/intAverage(intx,inty){intresult;result=(x+y)/2;returnresult;}教材168页函数定义?函数原型?调用?17变量的作用域•指在源程序中定义变量的位置及其能被读写访问的范围•分为–局部变量–全局变量教材170页18局部变量在语句块内定义的变量是内部变量,它只在本函数范围内有效,这种变量被称为局部变量.说明:(1)main()中定义的变量,也只在main()中有效(2)不同函数中可以使用相同名字的变量,他们代表不同的对象,互不干扰(3)形参也是局部变量,在本函数中有效(4)在复合语句中定义的变量,作用范围为该复合语句floatf1(inta){intb,c;…}charf2(intx,inty){intb,c;…}main(){intm,n;…}19例局部变量的作用范围voidother(void){inti=16,a=100;printf(--OTHER--\ni:%da:%d\n,i,a);}main(){inti=1,a=10,b=5;printf(--MAIN---\ni:%da:%db:%d\n,i,a,b);other();printf(--MAIN--\ni:%da:%db:%d\n,i,a,b);}20例5.8同名局部变量各自作用域#includestdio.hvoidGlobalPlusPlus(void);main(){intglobal=1;printf(BeforeGlobalPlusPlus(),itis%d\n,global);GlobalPlusPlus();printf(AfterGlobalPlusPlus(),itis%d\n,global);}voidGlobalPlusPlus(void){intglobal=1;printf(Before++,itis%d\n,global);global++;printf(After++,itis%d\n,global);}教材173页21全局变量在所有函数之外说明的变量称为外部变量,而外部变量是全局变量,它在所有函数中都是可见的。说明1.作用是增加了函数间数据的联系渠道,利用全局变量的这个特性,可以在函数间传递数据2.不在必要时不要使用全局变量3.在同一个源文件中外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即不起作用22例5.7#includestdio.hintglobal;/*定义全局变量*/voidGlobalPlusPlus(void);main(){global=1;printf(BeforeGlobalPlusPlus(),itis%d\n,global);GlobalPlusPlus();printf(AfterGlobalPlusPlus(),itis%d\n,global);}voidGlobalPlusPlus(void){printf(Before++,itis%d\n,global);global++;printf(After++,itis%d\n,global);}BeforeGlobalPlusPlus(),itis1Before++,itis1After++,itis2AfterGlobalPlusPlus(),itis2教材173页23例全局变量与局部变量同名#includestdio.hinta=3,b=5;max(inta,intb){intc;c=ab?a:b;return(c);}main(){inta=8;pirntf(%d,max(a,b));}24供用户使用的内存空间的情况程序和数据分开存放,数据分别存放在静态存储区和动态存储区用户区程序区静态存储区动态存储区静态存储区:全局变量全部存放在其中,在程序执行时给全局变量分配存储区,程序执行完毕就释放.动态存储区:存放(1)函数的形式参数:在调用时分配存储空间(2)自动变量(未加static声明的局部变量)(3)函数调用时的现场保护和返回地址(背诵)25变量的存储类型存储类型是指数据在内存中的存储方式.是编译器为变量分配内存的方式,它决定变量的生存期.分类:静态存储:系统给变量在程序运行期间分配固定的存储空间的方式动态存储:系统给变量在程序运行期间根据需要进行动态的分配存储空间的方式具体包含四种:自动的(auto),静态的(static)寄存器的(register),外部的(extern)26变量的存储类别•auto(自动)变量例如:intf(inta){autointc=3;…}包括函数中的定义的局部变量和函数形参。动态分配存储空间,在函数被调时分配,调用结束时自动释放存储空间。变量中的值被释放可以缺省教材174页27static(静态)局部变量•static(静态)局部变量例如:intf(inta){staticm=3;…}该局部变量占用的存储空间不释放,意味着保留该变量的原值属于静态存储类别,在静态存储区内分配存储单元,在程序的整个运行期间都不释放。在编译时赋初值,即只赋初值一次,以后每次调用函数时不再重新赋初值,而保留上次函数调用结束时的值。定义时如果不赋值,编译时自动赋初值为0。不能像全局变量一样被其他函数引用28例5.9#includestdio.hvoid