1、第6章 函 数通常,我们将相对独立,经常使用功效抽象为函数。函数包含库函数和用户自定义函数。C语言是经过函数来实现模块化程序设计。所以较大C语言应用程序,往往是由多个函数组成,即一个主函数和若干个子函数组成,每个函数分别对应各自功效模块。6.1 函数定义函数定义6.2 函数函数参数参数6.3 函数类型函数类型6.4 函数调用函数调用6.5 局部变量与局部变量与全局变量全局变量6.6 变量存放属性变量存放属性 6.7 内部函数与内部函数与外部函数外部函数第1页6.1 函数及其定义函数及其定义在程序设计过程中,通常将一个复杂人物划分为多个功效单一子任务,并用函数实现这些任务。调用其它函数函数称为主
2、调函数,被其它函数调用函数称为被调函数。主函数调用其它函数,其它函数之间也能够相互调用,同一个函数能够被一个或多个函数调用屡次。任何函数(包含主函数main())都是由函数说明和函数体两部分组成。例:函数调用main()func1();/调用func1函数/printf(“1,hello”);/调用printf函数/func1()/func1函数定义/func2();/调用func1函数/printf(“2,hello”);/调用printf函数/func2()/func1函数定义/printf(“3,hello”);/调用printf函数/6.1.1函数概述函数概述第2页6.1.2函数定义依
3、据函数是否需要参数,可将函数分为无参函数和有参函数两种。有参函数:主调函数与被调函数之间有数据传递关系。(如字符串处理函数)无参函数:普通用来执行一组操作,能够不带回函数值。(如max函数)(1)无参函数普通形式)无参函数普通形式函数类型函数名()说明语句部分;可执行语句部分;例:前面函数调用例子中func1和func2函数。注意注意:在旧标准中,函数能够缺省参数表。但在新标准中,函数不可缺省参数表;假如不需要参数,则用“void”表示,主函数main()例外。第3页(2)有参函数普通形式)有参函数普通形式形式1:函数类型函数名(数据类型参数1,数据类型参数2)说明语句部分;可执行语句部分;例
4、:doubleadd(doublex,doubley)doublez;z=x+y;return(z);这是一个用户自定义求和函数。x和y是形参,经过return(z)来实现向调用它函数返回add函数结果。第4页形式2:函数类型函数名(参数1,参数2)数据类型参数1;数据类型参数2;.说明语句部分;可执行语句部分;例:doubleadd(x,y)doublex,y;doublez;z=x+y;return(z);有参函数比无参函数多了一个参数表。调用有参函数时,调用函数将赋予这些参数实际值。为了与调用函数提供实际参数区分开,将函数定义中参数表称为形式参数表,简称形参表。第5页关于函数定义说明:1
5、.函数定义不允许嵌套函数定义不允许嵌套。在语言中,全部函数(包含主函数main())都是平行。一个函数定义,能够放在程序中任意位置,主函数main()之前或之后。但在一个函数函数体内,不能再定义另一个函数,即不能嵌套定义。main函数不能调用.2.类型说明符要求了函数类型,既函数返回值类型。它能够是任何简单类型,如整型,字符型,双精度型和指针型。函数返回值需要返回给主调函数处理,由return语句给出,如:return1。注意:对于不返回任何值函数最好说明其类型为void,这么能够增强编译器核查能力。3.函数名是一个程序员任意选择,满足c语言语法标识符。4.c程序执行从main函数开始,调用其
6、它函数后流程回到main函数,在main函数中结束整个程序运行.main函数是系统定义.第6页4.形式参数表中形参是用户自定义变量。形参个数多于一个,中间用逗号隔开,假如函数没有形参,则称为“无参函数”,定义无参函数小括号不能省略。形式参数作用是实现主调函数和被调函数联络,通常将函数所处理数据,影响函数功效原因作为形式参数。5.函数体包含函数申明后一对花括号中。在没有特殊说明时,函数体内定义变量均为局部变量,他们只在本函数执行时有定义,所以,不一样函数中局部变量能够同名,互不干扰。即使函数体中没有语句,花括号一样不能省。没有说明语句和执行语句函数称为空函数。例:voidfunc1();程序设计
7、中第一阶段只设计最基本模块,其它一些次要功效则在以后需要时补上.在程序编写开始阶段,能够在未来准备扩充功效地方写上一个空函数,表示先占一个位置,以后用一个编好程序代替它,这么程序结构清楚,以后扩充新功效方便,对程序结构影响不大.第7页案例7.1定义一个函数,用于求两个数中大数。/*功效:定义一个求较大数函数并在主函数中调用*/intmax(intn1,intn2)/*定义一个函数max()*/return(n1n2?n1:n2);main()intmax(intn1,intn2);/*函数说明*/intnum1,num2;printf(inputtwonumbers:n);scanf(%d%d
8、,&num1,&num2);printf(max=%dn,max(num1,num2);getch();/*使程序暂停,按任一键继续*/程序演示第8页6.2 函数参数函数参数6.2.1 形式参数与实在参数形式参数与实在参数1.形式参数与实在参数概念函数参数分为形参形参和实参实参两种,作用是实现数据传送。定义函数时参数称为形参。形参出现在函数定义中,只能在该函数体内使用。调用函数时参数称为实在参数。函数形式参数与实在参数能够是c语言允许任何类型。2.形式参数与实在参数结合C语言中,主调函数和被调函数之间是数据传递关系。被调函数未被调用时,被调函数形参没有实际值,并不占有内存空间。发生函数调用时,
9、才为形参分配存放单元,实参加形参结合。调用函数把实参值复制1份,传送给被调用函数形参,从而实现主调函数向被调用函数数据传送。实参加形参类型,个数必须相符。实参加形参结合方式有单向值传递和双向地址传递。第9页6.2.2实参加形参之间单向数值传递实参加形参之间单向数值传递当常量,变量或不表示式作为实参时,对应形参应是同类型变量。当发生函数调用时,形参被分配内存空间,实参将值传递给形参,这个过程是单向值传递。形参取得值之后,便与实参脱离关系,所以,形参改变不会影响到实参。例:从键盘输入两个整数,交换次序后输出voidswap(intx,inty)intz;z=x;x=y;y=z;main()inta
10、=4,b=8;swap(a,b);printf(“a=%2d,b=%2d”,a,b);运行结果:a=4,b=8第10页函数swap中,x和y为形参,类型为int型。主调函数中用swap(a,b);来调用该函数,a,b为实参,类型一样int型,实参加形参个数类型都一致.函数调用时,采取是单向值传递.形参x取a值4,y取b值8.x与y发生交换,形参发生交换却对实参a,b不起作用,函数调用结束后,回到main函数,a,b值仍为4和8.ababxyxy44884884第11页例:数组元素作为函数参数两个数组array1,array2,各有8个元素,将他们逐一相加,结果依然保留在array1中,程序以下
11、:main()intarray18,array28;int8;printf(“enterarray1:n”);for(i=0;i8;i+)scanf(“%d”,&array1i);printf(“enterarray2:n”);for(i=0;i8;i+)scanf(“%d”,&array2i);for(i=0;i8;i+)array1i=sum(array1i,array2i)/*调用sum函数*/for(i=0;i=1;i-)n=n+i;/*改变形参值*/printf(n_x=%dn,n);/*输出改变后形参值*/第14页说明:(1)实参能够是常量、变量、表示式、函数等。不论实参是何种类型
12、量,在进行函数调用时,它们都必须含有确定值,方便把这些值传送给形参。所以,应预先用赋值、输入等方法,使实参取得确定值。(2)形参变量只有在被调用时,才分配内存单元;调用结束时,即刻释放所分配内存单元。所以,形参只有在该函数内有效。调用结束,返回调用函数后,则不能再使用该形参变量。(3)实参对形参数据传送是单向,即只能把实参值传送给形参,而不能把形参值反向地传送给实参。(4)实参和形参占用不一样内存单元,即使同名也互不影响。第15页6.2.3地址传递方式值调用是单向传递,形参改变对实参不起任何作用,若要在子函数中对形参更改能对实参有效,可采取地址传递方式,即实参加形参指向同一段地址单元,经过传递
13、一个地址值方法来到达修改实参变量目标,被调用函数依据地址将数据写入对应存放单元.1.当变量地址值或指针变量作为实参,对应形参是同类型指针变量,2.当一维数组名做实参时,对应形参应是与其类型一致指针变量,能够有以下3种表示方式:设有:main()intx10;fun(x);/一维数组名做实参/第16页1)形参定义成一个一维数组:fun(inta10)或fun(a)inta10;2)形参定义成可变一维数组:fun(inta)或fun(a)inta;3)形参定义成指针变量:fun(int*p)或fun(p)int*p;3.当二维数组名做实参时,与一维数组名做实参相同,对应形参也必须是其类型相同指针类
14、型,一样有3种表示方式第17页设有:main()intx34;disp(x);1)形参定义成一个二维数组:disp(intnum34)或disp(num)intnum34;2)形参定义成第一维可变二维数组:disp(intnum4)或disp(num)intnum4;3)形参定义成指针变量:disp(int(*num)4)或disp(num)int(*num)34;第18页4.多维数组名作为函数参数与前述大致相同5.字符串作为实参,对应形参实类型为字符指针变量.因为字符串常量被隐含处理成无名字符型一维数组,传送该字符串首地址;字符串变量实际就是字符型一维数组,所以字符串做实参情况与一维数组名做
15、实参时相同.6.函数名或指向函数指针做实参,对应形参应为指向同类型函数指针,这时传递是函数入口地址.下面分别举例下面分别举例:例:编写程序,用函数实现统计成绩为80到89个分值学生人数(使用负数结束输入)#defineN40Fun(intarray,intnum10,intn)intk,t;for(k=0;k10;k+)numk=0;/数组num存放个分值人数,首先清0/for(k=0;k=80&a=89)scorei=a;i+;/数组s用来存放原始分数/fun(score,n,i);for(i=0;in2?n1:n2);第23页注意以下几个情况:1.若被调用函数定义在主调函数之后出现,就必须
16、在主调函数中对被调用函数加以说明,反之,则无需说明.因为在调用之前,编译系统已经知道了被调用函数函数类型、参数个数、类型和次序。例:intmax(intn1,intn2)/*定义一个函数max()*/return(n1n2?n1:n2);main()intnum1,num2;printf(inputtwonumbers:n);scanf(%d%d,&num1,&num2);printf(max=%dn,max(num1,num2);getch();/*使程序暂停,按任一键继续*/被调函数max置于主调函数main之前,则在主调函数中无需对max进行说明.第24页2.若被调用函数函数和调用函数不
17、在同一编译单位,则应按上述方式进行函数说明.3.若被调用函数函数值是整型或字符型,则可省略类型说明.4.若在全部函数之前申明了函数类型,则该函数原型在本程序文件中任何地方都有效.假如在全部函数定义之前,在函数外部(比如文件开始处)预先对各个函数进行了说明,则在调用函数中可缺省对被调用函数说明。floatf1();/函数类型说明/floatf2();/函数类型说明/.main()./无须进行函数类型说明/f1(x,y);/函数f1调用/f2(x,y);/函数f2调用/floatf1(inta,intb);/函数f1定义/floatf1(inta,intb);/函数f2定义/.第25页6.3.2返
18、回语句有参函数返回值,是经过函数中return语句来取得。(1)return语句普通格式:return(返回值表示式);或return;return返回值表示式;(2)return语句功效:返回调用函数,并将“返回值表示式”值带给调用函数。注意注意:调用函数中无return语句,并不是不返回一个值,而是一个不确定值。为了明确表示不返回值,能够用“void”定义成“无(空)类型”。第26页说明:1.一个函数中能够有多个return语句,但调用一次函数时只能执行其中一个.当执行到某个return语句时,程序控制流程返回主调函数,并将return语句中表示式值作为函数值带回.2.若函数体内没有ret
19、urn语句,就一直执行到函数体末尾,然后返回主调函数,这时也有一个不确定函数值被带回.此时,普通是经过指针或外部(全局)变量来进行数据传递.使用没有表示式return语句函数必须是void类型.3.若确定不要求带回函数值,则应将函数定义为void型,这么,禁止在主调函数中使用被调函数返回值.4.return语句中表示式类型应与函数申明类型一致.不一致时,则以函数类型为准,对于数值型数据,进行自动类型转换,即:函数类型决定返回值类型.假如缺省函数类型,则系统一律按整型处理。良好程序设计习惯良好程序设计习惯:为了使程序含有良好可读性并降低犯错,凡不要求返回值函数都应定义为空类型;即使函数类型为整型
20、,也不使用系统缺省处理。第27页6.4 函数调用函数调用 6.4.1函数调用普通形式函数调用普通形式在程序中,是经过对函数调用来执行函数体,其过程与其它语言子程序调用相同。1.调用子函数普通形式:语言中,函数调用普通形式为:函数名函数名(实际参数表实际参数表)切切记记:实参表中参数多于一个时,各参数之间用逗号隔开,实参个数、类型和次序,应该与被调用函数所要求参数个数、类型和次序一致,才能正确地进行数据传递。不然编译程序并不报错,但最终止果是错误。例:分析下面例子执行结果main()intx10;intyx;printf(”%d,%d”,(x+,y),y+);分析:在printf函数输出前,x1
21、1,y10。尽管printf函数输出是从左至右,但c语言计算函数参数次序是自右向左,所以,y值是10,计算y后值为11,表示式(x,y)值是11第28页2.函数调用方式在语言中,能够用以下几个方式调用函数:(1)函数表示式函数表示式。函数作为表示式一项,出现在表示式中,以函数返回值参加表示式运算。这种方式要求函数是有返回值。例:ypower(2,3);(2)函数语句)函数语句。C语言中函数能够只进行一些操作而不返回函数值,这时函数调用可作为一条独立语句。例:func1();/调用自定义函数/printf(”d”,a);/调用标准函数/(3)函数实参函数实参。函数作为另一个函数调用实际参数出现。
22、这种情况是把该函数返回值作为实参进行传送,所以要求该函数必须是有返回值。例:ypow(5,pow(4,3);第29页说明说明:(1)调用函数时,函数名称必须与含有该功效自定义函数名称完全一致。(2)实参在类型上按次序与形参,必须一一对应和匹配。假如类型不匹配,C编译程序将按赋值兼容规则进行转换。假如实参和形参类型不赋值兼容,通常并不给出犯错信息,且程序依然继续执行,只是得不到正确结果。(3)假如实参表中包含多个参数,对实参求值次序随系统而异。有系统按自左向右次序求实参值,有系统则相反。TurboC和MSC是按自右向左次序进行。第30页3.函数调用执行过程一个c语言源程序经过编译后,生成可执行代
23、码,形成exe可执行文件。存放在外存放器上(硬盘,软盘等)。当程序被开启时,首先从外存将程序代码装入内存,从主函数main起始处开始执行,若在程序执行过程中出现了对其它函数调用,则暂停当前途序执行,保留下一条指令地址(既返回地址),保留现场,然后转到被调函数入口地址执行被调函数,当被调函数结束或碰到return语句,则恢复原来所保留现场,并从原来所保留返回地址开始继续执行,直到main函数结束。mainfunc()func()结束返回15243第31页例:编写一个求an次方函数doublepower(doublea,intn);main()printf(“6tothepower3is%f”,p
24、ower(6.0,3);doublepower(doublea,intn);doublesval=1.0;while(n-)sval*=a;return(sval);运行结果:6tothepower3is216.000000函数调用是能够嵌套,而且c语言允许函数递归调用。第32页6.4.2 函数嵌套调用函数嵌套调用C语言函数定义是独立,相互平行,不允许在定义函数时,又包含另一个函数完整定义,既函数不能嵌套定义。函数允许嵌套使用。函数嵌套调用是指,在执行被调用函数时,被调用函数又调用了其它函数。这与其它语言子程序嵌套调用情形是类似,但主函数main不可被其它任何函数调用那个。其关系可表示如图。第
25、33页案例7.4计算s=1k+2k+3k+Nk/*功效:函数嵌套调用*/#defineK4#defineN5longf1(intn,intk)/*计算nk次方*/longpower=n;inti;for(i=1;ik;i+)power*=n;returnpower;第34页longf2(intn,intk)/*计算1到nk次方之累加和*/longsum=0;inti;for(i=1;i1)f=power(n-1)*n;elsef=1;return(f);第37页main()intn;longy;printf(inputainteagernumber:n);scanf(%d,&n);y=powe
26、r(n);printf(%d!=%ldn,n,y);getch();第38页6.5 局部变量与全局变量局部变量与全局变量 语言中全部变量都有自己作用域。变量说明位置不一样,其作用域也不一样,据此将语言中变量分为局部变量和全局变量。6.5.1 局部变量6.5.2 全局变量第39页6.5.1 局部局部变量变量对变量必须先定义后使用,在一个函数内部说明变量是局部变量,它只在该函数范围内有效。也就是说,只有在包含变量说明函数内部,才能使用被说明变量,在此函数之外就不能使用这些变量了。所以局部变量也称“内部变量”。第40页比如:intf1(inta)/*函数f1*/intb,c;/*a,b,c作用域:仅
27、限于函数f1()中*/intf2(intx)/*函数f2*/inty,z;/*x,y,z作用域:仅限于函数f2()中*/main()intm,n;/*m,n作用域:仅限于函数main()中*/第41页关于局部变量作用域还要说明以下几点:1主函数main()中定义内部变量,也只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义内部变量。因为主函数也是一个函数,与其它函数是平行关系。这一点是与其它语言不一样,应给予注意。2形参变量也是内部变量,属于被调用函数;实参变量,则是调用函数内部变量。3允许在不一样函数中使用相同变量名,它们代表不一样对象,分配不一样单元,互不干扰,也
28、不会发生混同。第42页例:p(intk)floatI,j;main()intI,j;q()floatj;形参k(形参也是局部变量),实型局部变量i,j有效范围整型局部变量i,j有效范围实型局部变量i,j有效范围第43页4在复合语句中也可定义变量,其作用域只在复合语句范围内。例:main()charr,s;inta,b,c;变量a,b,c有效范围.第44页6.5.2 全局全局变量变量在函数外部定义变量称为全局变量。也可称为外部变量。全局变量不属于任何一个函数,其作作用用域域是:从外部变量定义位置开始,到本文件结束为止。也就是说,在全局变量被定义之后每个函数都能够使用它。外部变量可被作用域内全部函
29、数直接引用。cn(intd).intq;/定义全局变量q/main()chara,b;q=0;.sn(floati)q+;.全局变量q有效范围第45页若希望在cn函数中也能使用全局变量q,则要在cn函数内部加语句“externintq”。关键字“extern”不是定义符,不对变量进行定义,只是对变量进行说明,说明该变量在某一处已经被定义,该函数直接使用。假如没有“extern”做说明,编译时会犯错,编译系统认为函数中使用这个变量没有被定义,所以普通将全局变量定义放在全部需要使用它函数之前。若在同一个源文件中出现全局变量与局部变量同名,则在局部变量有效范围内全部变量无效。例:inta=8;/定义
30、全局变量/f(inti)inta=3;printf(“%d,%d”,i,a);main()inti=3;f(i+a);运行结果为:11,3局部变量a,i有效范围,全局变量a无效局部变量i有效范围,全局变量a有效第46页案案例例7.9 输入长方体长(l)、宽(w)、高(h),求长方体体积及正、侧、顶三个面面积。/*功效:利用全局变量计算长方体体积及三个面面积*/ints1,s2,s3;intvs(inta,intb,intc)intv;v=a*b*c;s1=a*b;s2=b*c;s3=a*c;returnv;main()intv,l,w,h;clrscr();printf(ninputlengt
31、h,widthandheight:);scanf(%d%d%d,&l,&w,&h);v=vs(l,w,h);printf(v=%ds1=%ds2=%ds3=%dn,v,s1,s2,s3);getch();程序演示第47页对于全局变量还有以下几点说明:(1)外部变量可加强函数模块之间数据联络,但又使这些函数依赖这些外部变量,因而使得这些函数独立性降低。从模块化程序设计观点来看这是不利,所以不是非用不可时,不要使用外部变量。(2)在同一源文件中,允许外部变量和内部变量同名。在内部变量作用域内,外部变量将被屏蔽而不起作用。(3)外部变量作用域是从定义点到本文件结束。假如定义点之前函数需要引用这些外部
32、变量时,需要在函数内对被引用外部变量进行说明。外部变量说明普通形式为:extern数据类型外部变量,外部变量2;注意注意:外部变量定义和外部变量说明是两回事。外部变量定义,必须在全部函数之外,且只能定义一次。而外部变量说明,出现在要使用该外部变量函数内,而且能够出现屡次。第48页案例案例7.10 外部变量定义与说明。/*案例代码文件名:AL7_10.C*/intvs(intxl,intxw)externintxh;/*外部变量xh说明*/intv;v=xl*xw*xh;/*直接使用外部变量xh值*/returnv;main()externintxw,xh;/*外部变量说明*/intxl=5;/
33、*内部变量定义*/printf(xl=%d,xw=%d,xh=%dnv=%d,xl,xw,xh,vs(xl,xw);intxl=3,xw=4,xh=5;/*外部变量xl、xw、xh定义*/程序演示第49页6.6 变量动态存放与静态存放介绍变量动态存放与静态存放介绍 C语言程序占用存放空间如图。其中,程序区中存放是可执行程序机器指令;静态存放区中存放是需要占用固定存放单元变量;动态存放区中存放是不需要占用固定存放单元变量。变量定义包含3个方面内容:一是变量数据类型,如int,char。二是变量作用域,也就是变量有效范围。三是变量存放属性,既变量在内存中存放方法。不一样存放方法影响变量存在时间。在
34、语言中,对变量存放类型说明有以下四种:自动变量(auto)、存放器变量(register)、外部变量(extern)、静态变量(static)。自动变量和存放器变量属于动态存放方式,外部变量和静态内部变量属于静态存放方式。7.6.1 局部变量存放方式局部变量存放方式 7.6.2 全局变量存放方式全局变量存放方式程序区程序区静态存放区静态存放区动态存放区动态存放区第50页6.6.1 局部变量存放方式局部变量存放方式 依据局部变量存放区域,存放方式分为3种:1静态存放静态局部变量有时希望在函数调用结束后依然保留函数在中某局部变量值,则可将该局部变量定义为静态局部变量,用“static”定义,存放在
35、静态存放区。静态局部变量要保留上一次函数调用后值,就需要保留原来存放空间,也就是说函数调用结束后并不释放静态局部变量存放空间,使静态局部变量值能构保持连续性。(1)定义格式:static数据类型内部变量表;例:局部变量静态存放方式voidst()staticints=1;/定义静态局部变量/printf(“s=%dn”,s);s+;第51页main()inti;for(i=0;i3;i+)st();运行结果:s1s2s3对于上面例子依据静态局部变量下面4个特征来了解:1)定义但不初始化,则自动赋以“”(整型和实型)或0(字符型);而自动变量定义后如没赋值,他值是所分配存放空间原来存放值,是一个
36、不确定值。比如:main()staticintm;printf(“%d”,m);运行结果为:0第52页2)不论函数调用多少次,静态局部变量初始化语句只对其赋值一次,因为静态局部变量是在编译时赋初值,在程序运行时它已经有初值,每次调用函数时就不在重新赋值,而是保留上一次函数调用结束后值。不过对于自动变量,函数每调用一次就要重新赋一次初值,前例中函数st一共被主函数调用了3次,每一次调用结束后静态局部变量s值都不一样,也就意味着每一次开始调用时s初值也不一样。3)静态内部变量属于静态存放。在程序执行过程中,即使所在函数调用结束也不释放。换句话说,在程序执行期间,静态内部变量一直存在,但其它函数是不
37、能引用它们。4)静态局部变量依然是局部变量,其它函数不能使用它。何时使用静态内部变量何时使用静态内部变量1)需要保留函数上一次调用结束时值。2)变量只被引用而不改变其值。第53页2动态存放动态存放自动局部变量(又称自动变量)函数种定义局部变量,如没有尤其指定其存放属性,那么它就是自动变量,自动变量用关键字auto定义。auto可省略。(1)定义格式定义格式:auto数据类型变量表;例:intmax(intm,intn)autointz;/定义自动变量z,也可定义为intz;/.(2)存放特点存放特点1)自动变量属于动态存放方式。在函数中定义自动变量,只在该函数内有效;函数被调用时分配存放空间,
38、调用结束就释放。在复合语句中定义自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,不然将引发错误。2)定义而不初始化,则其值是不确定。假如初始化,则赋初值操作是在调用时进行,且每次调用都要重新赋一次初值。第54页3)因为自动变量作用域和生存期,都局限于定义它个体内(函数或复合语句),所以不一样个体中允许使用同名变量而不会混同。即使在函数内定义自动变量,也可与该函数内部复合语句中定义自动变量同名。提议:提议:系统不会混同,并不意味着人也不会混同,所以尽可能少用同名自动变量!例:局部变量自动存放方式intsum(intx,inty)inta;/定义自动变量/a=x+y;return(a
39、);main()inta=5,b=8;/对自动变量进行初始化/printf(“%dn”,sum(a,b);运行结果:13此例题中,函数sum没有被调用时和调用返回后,内存中不存在sum自动变量a及形参x,y第55页案例案例7.13自动变量与静态局部变量存放特征。voidauto_static(void)intvar_auto=0;/*自动变量:每次调用都重新初始化*/staticintvar_static=0;/*静态局部变量:只初始化1次*/printf(“var_auto=%d,var_static=%dn”,var_auto,var_static);+var_auto;+var_stat
40、ic;main()inti;for(i=0;i5;i+)auto_static();第56页3存放器方式存放存放器方式存放存放器变量普通情况下,变量值都是存放在内存中。为提升执行效率,语言允许将局部变量值存放到运算器中存放器中,能够将这些变量定义为存放器类型,这种变量就称为存放器变量。定义格式以下:register 数据类型变量表;例:局部变量存放器存放方式main()registerintx=0;intn,i;scanf(“%d”,n);for(i=1;i=n;i+)x+=i;运行时输入5,得到15(1)静态局部变量和全局变量不能存放在存放器中,也就是说存放器不能以静态方式存放变量。(2)对
41、存放器变量实际处理,随系统而异。比如,微机上MSC和TC将存放器变量实际看成自动变量处理。(3)允许使用存放器数目是有限,不能定义任意多个存放器变量。能够保留在存放器中变量数据类型只有char,shortint,unsignedint,int和指针类型。第57页6.6.2 全局变量存放方式全局变量存放方式全局变量都是存放在静态存放区,在程序运行整个过程中都占有存放空间,定义全局变量越多,程序运行效率越低,无须要时不要使用全局变量。全局变量属于静态存放方式:(1)静静态态方方式式:用static定义了全局变量称为静态外部变量只允许被根源文件中函数引用,即只能被定义此变量文件使用。其它文件不能用它
42、。其定义格式为:static数据类型外部变量表;文件a1.c内容以下:staticints;main()其它文件即使使用了语句“externints”,也不能使用静态外部变量s。第58页例:全局变量静态存放方式intx;voidfirst(inta)a+;printf(“fa=%dn”,a);voidsecond(inta)staticintb=2;x=b+=a;printf(“sa=%d,sb=%d,x=%dn”,a,b,x);main()inta=1;first(a);for(;a3;a+)second(1);second(x);第59页运行结果:fa=2sa=1,sb=3,x=3sa=1
43、,sb=4,x=4sa=4,sb=8,x=8(2)外部方式)外部方式允许被其它源文件中函数引用允许被其它源文件中函数引用定义时缺省static关键字全局变量,即为外部变量。在组成一个程序全部文件中都能够使用外部变量。其它源文件中函数,引用非静态外部变量时,需要在引用函数所在源文件中进行说明:extern数据类型外部变量表;注意注意:在函数内extern变量说明,表示引用根源文件中外部变量!而函数外(通常在文件开头)extern变量说明,表示引用其它文件中外部变量第60页定义位置定义位置存放方式存放方式存放区域存放区域存放时间存放时间全局变量全局变量外部变量外部变量静态外部变量静态外部变量静态存
44、放区静态存放区程序运行全过程序运行全过程程局部变量局部变量静态局部变静态局部变量量自动变量自动变量存放器变量存放器变量动态存放区动态存放区存放器存放器调用函数全过调用函数全过程程第61页静态局部变量和静态外部变量同属静态存放方式,但二者区分较大:(1)定义位置不一样。静态局部变量在函数内定义,静态外部变量在函数外定义。(2)作用域不一样。静态局部变量属于内部变量,其作用域仅限于定义它函数内;即使生存期为整个源程序,但其它函数是不能使用它。静态外部变量在函数外定义,其作用域为定义它源文件内;生存期为整个源程序,但其它源文件中函数也是不能使用它。(3)初始化处理不一样。静态局部变量,仅在第1次调用
45、它所在函数时被初始化,当再次调用定义它函数时,不再初始化,而是保留上1次调用结束时值。而静态外部变量是在函数外定义,不存在静态内部变量“重复”初始化问题,其当前值由最近1次给它赋值操作决定。第62页务务必必切切记记:把局部变量改变为静态内部变量后,改变了它存放方式,即改变了它生存期。把外部变量改变为静态外部变量后,改变了它作用域,限制了它使用范围。所以,关键字“static”在不一样地方所起作用是不一样。第63页6.7 内部函数和外部函数内部函数和外部函数 7.5.1 内部函数(又称静态函数)内部函数(又称静态函数)7.5.2 外部函数外部函数 7.5.3 多个源程序文件编译和连接多个源程序文
46、件编译和连接c语言程序能够由多个函数组成,这些函数能够在一个文件中,也能够分散在多个文件中,在一个文件中函数能够相互调用,可知函数都是全局。不在一个文件中函数也能够相互调用,这和全局变量相同。当一个源程序由多个源文件组成时,语言依据函数能否被其它源文件中函数调用,将函数分为内部函数内部函数和外部函数外部函数。第64页6.7.1 内部函数(又称静态函数)内部函数(又称静态函数)假如在一个源文件中定义函数,只能被本文件中函数调用,而不能被同一程序其它文件中函数调用,这种函数称为内部函数。定义一个内部函数,只需在函数类型前再加一个“static”关键字即可,以下所表示:static函数类型函数名(函
47、数参数表)关键字“static”,译成汉字就是“静态”,所以内部函数又称静态函数。但此处“static”含义不是指存放方式,而是指对函数作用域仅局限于本文件。使用内部函数好处是:内部函数在文件中定义和调用遵照普通函数定义和调用规则,只是不能在其它文件中被调用。不一样人编写不一样函数时,不用担心自己定义函数,是否会与其它文件中函数同名,因为同名也没相关系。第65页6.7.2 外部函数外部函数外部函数定义:在定义函数时,假如没有加关键字“static”,或冠以关键字“extern”,表示此函数是外部函数。外部函数能够被定义它文件调用,还可被其它文件调用:extern函数类型函数名(函数参数表)调用
48、外部函数时,需要对其进行说明:extern 函数类型函数类型 函数名函数名(参数类型表参数类型表),函数名,函数名2(参数类型表参数类型表2);案例案例7.11外部函数应用。(1)文件mainf.cmain()externvoidinput(),process(),output();input();process();output();第66页(2)文件subf1.cexternvoidinput()/*定义外部函数*/(3)文件subf2.cexternvoidprocess()/*定义外部函数*/(4)文件subf3.cexternvoidoutput()/*定义外部函数*/第67页6.8
49、 带参数宏带参数宏 所谓编译预处理是指,在对源程序进行编译之前,先对源程序中编译预处理命令进行处理;然后再将处理结果,和源程序一起进行编译,以得到目标代码。编译预处理是c编译系统一个组成部分,宏定义就是c提供一个预处理功效。依据宏定义内容,宏定义可分为两种形式:1.符号常量定义程序中所使用常量普通都含有一定意义,有时在程序中直接使用却无法突出其意义;或者程序中有一部分内容重复出现,但书写频繁,为了提升程序可读性,就能够使用宏定义,用宏名来表示常量。带参宏定义普通格式带参宏定义普通格式#define宏名(形参表)语言符号字符串第68页3说明说明(1)宏名普通用大写字母表示,以示与变量区分。但这并
50、非是要求。(2)宏定义不是语句,所以不能在行尾加分号。不然,宏展开时,会将分号作为字符串1个字符,用于替换宏名。例:#defineYES1#defineSPscanf(“%d”,&x);printf(“%d”,x);(3)在宏展开时,预处理程序仅以按宏定义简单替换宏名,而不作任何检验。若有错误,只能由编译程序在编译宏展开后源程序时发觉。(4)宏定义命令#define出现在函数外部,宏名有效范围是:从定义命令之后,到本文件结束。通常,宏定义命令放在文件开头处。但用undef命令可中止宏定义作用,例defineE10#defineFfalse.F有效范围E有效范围#defineF.第69页例:从键