计算机C语言-第八章.ppt

上传人:zhu****ei 文档编号:3589745 上传时间:2019-12-18 格式:PPT 页数:122 大小:726KB
返回 下载 相关 举报
计算机C语言-第八章.ppt_第1页
第1页 / 共122页
计算机C语言-第八章.ppt_第2页
第2页 / 共122页
计算机C语言-第八章.ppt_第3页
第3页 / 共122页
点击查看更多>>
资源描述
第8章函数8.1概述一个C程序,由一个主函数和若干其它函数组成,它们之间的关系是:主函数可以调用其它函数,其它函数可相互调用。且一个函数可以被调用若干次注:每个函数都是独立的,平等的!函数:完成特定功能的程序段,通常由用户定义或系统定义各函数可存放在一个文件中,也可以存放在不同的文件中。,某程序整体结构,,程序运行轨迹:mainadaeamainbfefbgbhbmainchghcicmain,举例:用常规、文件包含两种方法打印字符串一、常规方法:各函数包含在一个文件中例T8-1.cmain()p1();p2();p1();p1()printf(“*n”);p2()printf(“_How_do_you_do!n”);,运行结果:*_How_do_you_do!_*,二、文件包含的方法在主函数所在的文件中使用文件包含预编译命令,将不在本文件而在其它文件中的函数进行预编译处理,把各文件中的函数包含到本文件中来,然后一起进行编译、连接、运行。T8-1-3.c#include“T8-1-1.c”#include“T8-1-2.c”main()p1();p2();p1();运行结果同上友情提示:还可以用项目的方法,T8-1-1.cp1()printf(“*n”);,T8-1-2.cp2()printf(“_How_do_you_do!n”);,说明:(1)一个文件可含多个函数,编译的单位是文件而不是函数;(2)一个完整的程序可由若干个文件组成,可用项目或文件包含的方法对其编译;(3)C执行总是从main函数开始执行,调用其它函数后又返回到main函数;(4)函数定义是独立的、平等的,不能嵌套定义(即函数里不能再定义函数)但可相互调用;(5)函数的类型:标准库函数,由系统提供,用户直接使用用户定义的函数(6)函数的形式:无参函数主调函数无数据传给被调函数,可带或不带返回值.有参函数主调函数与被调函数间有参数传递,主调函数可将实际参数传送给被调函数的形式参数,被调函数的函数值可传回主调函数。,8.2函数定义的一般形式1.无参函数的定义形式:类型标识符函数名()声明部分语句部分注:无参函数一般不返回函数值,故类型标识符可省。2.有参函数的定义形式:类型标识符函数名(形式参数表列)声明部分语句部分,其中:类型标识符:指出函数返回值的数据类型(int,float,char等),系统默认为int函数名:合法的标识符;形参表列:接收主调函数传递过来的实参,其中包括对形参类型的声明(老版本中形参类型进一步声明放在下一行)。形参类型:与实参类型要一致。:称函数体,包括声明部分:定义局部变量的数据类型;语句部分:完成函数功能的若干执行语句。,例:intmax(intx,inty)intz;z=xy?x:y;return(z);,3.空函数的定义形式类型说明符函数名()例:p1()空函数不作任何操作,但是合法,它对调试程序或以后在此处补充完整的函数体是有作用的。,4.对形参声明的传统方式传统方式中,形参类型说明在函数定义的第2行如:传统形参声明形式intmax(x,y)intx,y;intz;z=xy?x:y;return(z);,新版本形参声明形式intmax(intx,inty)intz;z=xy?x:y;return(z);,以上两种定义形式在TurboC中都认可,8.3函数参数和函数的值8.3.1形式参数和实际参数实际参数:主调函数中提供的数据。可以是常量、变量、表达式等,是具体的数值。形式参数:被调函数中用以接收主调函数数据的变量。被调用函数名后面括号内的若干变量名。,例T8-2.c调用函数时的数据传递main()inta,b,c;scanf(%d%d”,输入:-100200Maxis200,关于形、实参的说明:1.形参只有在函数调用时才分配存储单元,调用结束后,释放所分配的单元;2.实参可以是常量、变量、表达式:max(3,a+b),总之要有确定的值,当函数调用时,将实参的值传递给形参,若是数组名,则传送的是数组的首地址。3.被调函数中,形参类型必须指定,以便分配存储单元。,4.实参、形参的数据类型一致,赋值要兼容,顺序要一致。如果形、实参类型不一致时,则按赋值规则进行。通常被调函数放在主调函数之前,以便编译系统对函数类型和形参类型作合法性检查。若被调函数在主调函数之后,一般要对被调函数作原型声明。main()floata=4.5,b=4.5;intabc(int,int);abc(a,b);abc(intx,inty)printf(“x=%d,y=%dn”,x,y);结果:x=4,y=4,5.若被调函数类型为非整形或实参形参类型不匹配,要在主调函数中对被调函数作原形声明。另外若被调函数在主调函数之前定义,则原形声明可省,因为编译系统已经知道被调函数的类型及其形参的个数、类型了。6.实参对形参的数据传送是值传送,也是单向传送,当被调函数的形参发生变化时,并不改变主调函数实参的值。,例T8-2-1.c形、实参占据的是不同的存储单元main()inta=2,b=3;printf(“a=%d,b=%dn”,a,b);printf(“,运行结果:a=2,b=3elsereturn(b);3.return后面的括号可省,如:returna;,4.return后的值可以是一个表达式,如:return(xy?x:y);5.函数值的类型是在定义函数时指定的如:intmax(x,y)floatmin(a,b)doubleabc(d1,d2)6.语句return(a,b,c)是合法的,返回表达式c的值。注意:(1)函数定义时,函数名的括号后无“;”;(2)未加类型说明的函数自动按整型处理;(3)定义函数时,函数值的类型一般与return后面表达式的类型一致,若不一致,则以函数值为准。,例T8-3.c函数值类型为整型,而返回值的类型是实型,最后以整型值返回。即以函数类型为准main()intmax(float,float);/*原型声明*/floata,b;intc;scanf(“%f%f”,输入:1.52.5输出:maxis2,6.函数中无return语句时,可能返回一个不确定或无用的值例T8-3-1.cmain()inta,b,c;a=p1();b=p2();c=p1();printf(“a=%d,b=%d,c=%dn”,a,b,c);p1()printf(“*n”);p2()printf(“Iamhappy!n”);,运行结果:*Iamhappy!*a=6,b=12,c=6,7.为明确表示不带返回值,可用void(无值,空类型)定义函数。例T8-3-2.cmain()inta,b,c;a=p1();b=p2();c=p1();printf(“a=%d,b=%d,c=%dn”,a,b,c);voidp1()printf(“*n”);voidp2()printf(“Iamhappy!n”);,编译时指出:Typemismatchinredeclartionofp1,p2意即:在定义函数p1,p2时类型不匹配,8.4函数的调用主调函数:主动去调用其它函数被调函数:被其它函数所调用8.4.1函数调用的一般形式函数名(实参表列)操作:把控制和实参传送给被调函数,当无参时,实参表列为空,但()不能省。函数名:是已存在的被调用的函数;实参表列:有确定值的数据,当有多个实参时,实参间用“,”分隔,通常形实、参个数要相等,类型要一致,实参求值顺序在TurboC中是从右向左。,例T8-4.c实参求值顺序从右向左main()inti=2,p;p=f(i,+i);printf(“p=%d,i=%dn”,p,i);intf(inta,intb)intc;if(ab)c=1;elseif(a=b)c=0;elsec=-1;return(c);,运行结果:p=0,i=3若将参数改为f(i,i+),则结果为:p=1,i=3思考:若从左至右呢?回忆一下printf的求值顺序,8.4.2函数的调用方法1.函数语句:把函数调用作为一个单独的语句;如:f1();2.函数表达式:函数调用出现在表达式中,其函数返回的值参加整个表达式的运算。如:c=max(a,b)+min(c,d);3.函数参数:函数调用作为另一个函数的参数,如:m=max(a,max(b,c);printf(“%d”,max(a,b);,8.4.3对被调用函数的声明和函数原型被调函数应具备的条件1.被调函数必须存在(标准或用户定义),如不在同一文件中,可用项目或文件包含的方法将各被调用函数连接起来。2.若使用库函数,应在文件开头用#include命令将调用库函数时用到的宏定义信息包含到本文件中来。如:#include“stdio.h”#include“math.h”3.若主调和被调函数在同一文件中,一般应在主调函数中对被调函数的类型作声明,即向编译系统声明即将调用的函数形式:类型标识符被调用函数名(类型形参.);,例T8-5.c在主调函数中,对被调函数的数据类型进行说明main()floatadd(floatx,floaty);/*声明:函数类型、名,形参类型等通知编译系统*/再看floata,b,c;scanf(%f%f”,输入:3.66.5输出:sumis10.10000,问题:(1)若不对函数类型进行声明,则指出:在重定义函数add时,类型不匹配;(2)在声明时指出类型,若定义时没有指出类型,编译指出:定义add时类型不匹配(此处是实型)。函数声明(原型):与函数首部一致。顺序、个数、类型等都要相同有关函数的定义、声明、返回值等概念1.函数定义:对函数功能的确定,指定函数名、函数值类型、形参及类型、函数体等,它是完整的、独立的函数单位。,2.函数声明:也称函数原型,其作用是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便调用函数时进行对照检查。函数声明(原型)的形式:(1)函数类型函数名(参数类型1,参数类型2.);(2)函数类型函数名(参数类型1参数名1,参数类型2参数名2.);3.当函数返回的值为整型或字符型时,可不必声明。系统会默认把第一次碰到的函数视为INT4.被调用函数在主调函数之前定义时,在主调函数中可不必声明。,友情提示1,函数的原型声明必须放在程序开始处或main之前,例T8-5-1.c被调函数出现在主调函数之前,则在主调函数中不必声明floatadd(floatx,floaty)floatz;z=x+y;return(z);main()floata,b,c;scanf(“%f%f”,输入:3.66.5输出:sumis10.100000,主调函数中没对被调函数的返回值进行类型声明,原因是:编译系统已经预知定义的函数的类型,并进行自动处理。5.如果在所有函数定义之前,在文件的开头,在函数的外部对函数的类型作了声明,则在各主调函数中不必对所调用的函数再作类型声明。例T8-5-2.c在文件的开头,在所有函数的外部对函数作类型声明。chara1(charx1,charx2);floata2(floaty1,floaty2);inta3(intm);doublea4(doublen1,doublen2);,main()返回charc1=d,c2=a;inti=5;floatf1=3.67,f2=5.56;doubled1=11111111.111,d2=22222222.222;printf(“a1()=%cn”,a1(c1,c2);printf(“a2()=%fn”,a2(f1,f2);printf(“a3()=%dn”,a3(i);printf(“a4()=%lfn”,a4(d1,d2);chara1(charx1,charx2)return(x1x2?x1:x2);floata2(floaty1,floaty2)floatz;z=y1+y2;return(z);inta3(intm)inti,s=1;for(i=1;i=m;i+)s=s*i;return(s);doublea4(doublen1,doublen2)doublen3;n3=n1+n2;return(n3);,运行结果:a1()=da2()=9.230000a3()=120a4()=33333333.333000问题的提出:(1)不在文件开头,不在函数外部说明,情况如何?(2)不在主调函数开始部分说明,解决的办法?,友情提示2,不要将空函数和void函数弄混了,8.5函数的嵌套调用,例T8-6用弦截法求方程x3-5x2+16x=0的根(请仔细研究),方法与步骤:2.连接f(x1),f(x2)两点成一直线(弦),此线交x轴于x。X点的坐标求法:连接f(x1),f(x2)两点的直线f(x)称商差(弦、斜率):求x点的坐标从x值得f(x)3.若f(x)与f(x1)同号,则根必在(x,x2)区间,此时将x作新的x1;若f(x)与f(x2)同号,则根必在(x1,x)区间,此时将x作新的x2;4.重复步骤2,3直到|f(x)|=0.0001);return(x);main()floatx1,x2,f1,f2,x;doprintf(“inputx1,x2:n”);scanf(“%f%f”,运行:inputx1,x2:2,6Arootofequationis5.0000,8.6函数的递归调用递归:在函数调用过程中,直接或间接的调用自身。1.直接递归:在函数体内又调用自身,2.间接递归:当函数去调用另一函数时,而另一函数反过来又调用自身。解决无终止递归调用的方法是:确定好结束递归的条件。,递归调用定义:函数直接或间接的调用自身叫函数的递归调用,说明C编译系统对递归函数的自调用次数没有限制所以,必须要用if语句限制递归的次数,以免无限递归下去了,intf(intx)inty,z;z=f(y);.return(2*z);,例T8-7.c有5个人在一起问年龄,第5个人比第4个人大2岁,第4个人比第3个人大2岁.第2个人比第1个人大2岁,第1个人为10岁。(回推+递推),T8-7.c问年龄程序age(intn)intc;if(n=1)c=10;elsec=2+age(n-1);return(c);/*返回给主调函数*/main()printf(“%dn”,age(5);,运行结果:18,在递归调用过程中,有些信息被临时压入堆栈回推到已知:结束这里控制有限次递归的一个条件就是if(n=1),有些问题,可以用递推,也可以用递归的方法解决递推:从一个已知的事实出发,按一定规律推出下一个事实,再从已知的新的事实,推出下一个新的事实.例T8-7-1.c用递推法求n!,即从1开始,乘2,乘3.一直到nmain()inti,s=1;for(i=1;i=5;i+)s=s*i;printf(“s=%dn”,s);,运行结果:s=120,递归:回推(问题先压入堆栈暂存)+递推从哪里开始递推?从满足结束递归的条件处开始递推如:5!=5x4!4!=4x3!3!=3x2!2!=2x1!1!=10!=1,例T8-8.c用递归法求4!floatfacto(intn)floats;if(nb若nk,认为数组ab若n=k,认为数组a=b,2、数组名作为函数实参此时,传送的是数组的地址,调用函数时,对形参数组元素的操作,实际上也是对实参数组元素的操作。*地址传递*在主调函数与被调函数分别定义数组,且类型应一致,例求学生的平均成绩,#includefloataverage(intstu10,intn);voidmain()intscore10,i;floatav;printf(Input10scores:n);for(i=0;i10;i+)scanf(%d,floataverage(intstu10,intn)inti;floatav,total=0;for(i=0;in;i+)total+=stui;av=total/n;returnav;,实参用数组名,形参用数组定义,intstu,几点说明:1.数组名作形、实参数时,应分别在主、被调函数中对其定义2.数组名作参数时,传递的是地址,对形参数组的操作实际上也是对实参数组的操作。两个数组是共用同一个内存单元则形参中的数据变化了实参也会变化这与变量做形参区别很大3.作为形、实参数的数组,其类型要一致,大小一般相等,以保证形式上的对应;4.当形参数组大小未指定时,用一实参将数组长度传递给形参以便对数组进行操作;5、字符串的传递同数组的传递字符串是用数组存储的,例8-12.c求两组学生的平均成绩,形参数组长度缺省floataverage(floata,intn)inti;floataver,sum=a0;for(i=1;in;i+)sum=sum+ai;aver=sum/n;return(aver);,main()floats15=98.5,97,91.5,60,60,55;floats210=67.5,89.5,99,69.5,77,89.5,76.5,54,60,99.5;printf(“theaverageofclassAis%6.2fn”,average(s1,5);printf(“theaverageofclassBis%6.2fn”,average(s2,10);,theaverageofclassAis80.40theaverageofclassBis78.20,例数组元素与数组名作函数参数比较,#includevoidswap2(intx,inty)intz;z=x;x=y;y=z;main()inta2=1,2;swap2(a0,a1);printf(a0=%dna1=%dn,a0,a1);,值传递,#includevoidswap2(intx)intz;z=x0;x0=x1;x1=z;main()inta2=1,2;swap2(a);printf(a0=%dna1=%dn,a0,a1);,地址传递,例数组元素与数组名作函数参数比较,例数组排序-简单选择排序(请同学们自行思考),9,49,i=0,例数组排序-简单选择排序,13,68,i=1,i=8,例数组排序-简单选择排序,例求二维数组中最大元素值,intmax_value(intarray34)inti,j,k,max;max=array00;for(i=0;imax)max=arrayij;return(max);main()inta34=1,3,5,7,2,4,6,8,15,17,34,12;printf(maxvalueis%dn,max_value(a);,例求二维数组中各行元素之和,get_sum_row(intx3,intresult,introw,intcol)inti,j;for(i=0;irow;i+)resulti=0;for(j=0;jcol;j+)resulti+=xij;main()inta23=3,6,9,1,4,7;intsum_row2,row=2,col=3,i;get_sum_row(a,sum_row,row,col);for(i=0;irow;i+)printf(Thesumofrow%d=%dn,i+1,sum_rowi);,18,12,8.8局部变量和全局变量8.8.1局部变量变量:按其作用域,可分为局部和全局局部:作用域仅限于其所定义的函数或复合语句内部,离开该函数或复合语句则释放内存单元特点:(1)在不同的函数中允许同名,它们占据不同的内存单元,相互之间互不影响。(2)形参属局部变量,只能在其所在的函数内部使用。,例T8-14-1.cf1()inta=10,b=25,c=30;printf(“f1:a=%d,b=%d,c=%dn”,a,b,c);f2(inta,intb)intc;a=a+2;c=a+b+3;printf(“f2:a=%d,b=%d,c=%dn”,a,b,c);main()inta=1,b=2,c=5;/*abc也不例外,也是局部变量*/printf(“1.main:a=%d,b=%d,c=%dn”,a,b,c);f1();printf(“2.main:a=%d,b=%d,c=%dn”,a,b,c);f2(a,b);printf(“3.main:a=%d,b=%d,c=%dn”,a,b,c);,运行结果:1.main:a=1,b=2,c=5f1:a=10,b=25,c=302.main:a=1,b=2,c=5f2:a=3,b=2,c=83.main:a=1,b=2,c=5,例T8-14-2.c复合语句中局部变量的例子main()inta=1,b=2,c=3;intc;c=a-b;printf(“a=%d,b=%d,c=%dn”,a,b,c);printf(“a=%d,b=%d,c=%dn”,a,b,c);,运行结果:a=1,b=2,c=-1a=1,b=2,c=3,8.8.2全局变量全局变量:在一个文件的所有函数以外定义的变量称为外部或全局变量。作用域:从定义变量的位置开始到源程序结束。所有该源文件中的函数公用,几点说明,在源程序开始定义的全局变量,对源程序中所有函数有效在源程序中间定义的全局变量,仅对其后面的所有函数有效,几点说明2,在函数或复合语句中定义的局部变量若与全局变量同名,当该函数或复合语句被执行时,则局部变量优先,全局变量不起作用(被屏蔽)。,例T8-14-3.c全局变量的作用域及其使用情况inta=1;f1()intb;b=a+3;printf(“f1:a=%d,b=%dn”,a,b);f2()inta,b;a=5;b=a+3;printf(“f2:a=%d,b=%dn”,a,b);f3()intb;a=6;b=a+3;printf(“f3:a=%d,b=%dn”,a,b);main()intb=3;printf(“1.main:a=%d,b=%dn”,a,b);f1();printf(“2.main:a=%d,b=%dn”,a,b);f2();printf(“3.main:a=%d,b=%dn”,a,b);f3();printf(“4.main:a=%d,b=%dn”,a,b);,运行:1.main:a=1,b=3f1:a=1,b=42.main:a=1,b=3f2:a=5,b=83.main:a=1,b=3f3:a=6,b=94.main:a=6,b=3,几点说明3,全局变量的使用,增加了函数间数据联系的渠道,同一文件中的所有函数都能引用全局变量的值,当某函数改变了全局变量的值时,便会影响其它的函数。,例T8-15.c用一维数组存放10个学生的成绩,在函数中求最高分、最低分和平均值。floatmax=0,min=0;(习惯上:Max,Min)floataverage(floatarray,intn)inti;floataver,sum=array0;max=min=array0;for(i=1;imax)max=arrayi;elseif(arrayimin)min=arrayi;sum=sum+arrayi;aver=sum/n;return(aver);,main()floatave,score10;inti;printf(“input10numbers:n”);for(i=0;i10;i+)scanf(“%f”,一个函数可以返回3个值了!,运行:input10numbers:9945789710067.589926643max=100.00min=43.00ave=77.65,floatmax,min;floataverage(floatarray,intn)inti;floatsum=array0;max=min=array0;for(i=1;imax)max=arrayi;elseif(arrayimin)min=arrayi;sum+=arrayi;return(sum/n);main()inti;floatave,score10;/*Input*/ave=average(score,10);printf(max=%6.2fnmin=%6.2fnaverage=%6.2fn,max,min,ave);,外部(全局)变量的弊端:1.建议非必要时不要使用全局变量:(1)整个程序中均占用存储空间(2)函数可移植性差2.程序可读性差,且一旦外部变量被改变将影响所有函数,inti;main()voidprt();for(i=0;i5;i+)prt();voidprt()for(i=0;i5;i+)printf(“%c”,*);printf(“n”);,例外部变量副作用,运行结果:*,变量的存储属性概述每个变量有两个基本属性:变量的数据类型!那么,变量的存储类型呢?,编译或函数调用时为其分配内存单元,10,程序中使用变量名对内存操作,变量的属性数据类型:变量所持有的数据的性质(操作属性)存储属性存储器类型:寄存器、静态存储区、动态存储区生存期:变量在某一时刻存在-静态变量与动态变量作用域:变量在某区域内有效-局部变量与全局变量变量的存储类型auto-自动型register-寄存器型static-静态型extern-外部型变量定义格式:存储类型数据类型变量表;,如:intsum;autointa,b,c;registerinti;staticfloatx,y;,程序运行时,在内存中的存储情况:(1)静态存储方式:即程序运行期间为其分配的存储单元是固定的。直到文件执行完(2)动态存储方式:程序运行期间根据需要为其分配存储单元。用完就释放,格式:autointa;说明符“auto”可以省略。autofloatpi;说明:1.说明自动变量必须在一个函数体的内部。2.函数的形参也是自动变量。,作用域函数内部,实质上是一个局部变量。只有在函数被调用时才存在,从函数中返回时即消失,其值仅限于说明它的函数。由于自动变量具有局部性,所以在两个不同的函数中可以分别使用同名的变量而互不影响。,自动变量auto,8.9.2auto变量函数内部无static声明的局部量均为动态存储类别,被分配在动态区。自动存储类别的声明符auto可省;自动变量被分配在动态区,每次调用重新分配空间。用完释放,其值也消失。例如:intf(inta)autointb,c=3;/*定义b、c为自动变量*/上述变量定义与以下定义等价:intb,c=3;,8.9.3用static声明局部变量若希望函数调用结束后,其值不消失,下次调用函数时继续使用上次已有的值,则用static对变量加以声明。思考:全局变量需要专门声明static吗?例T8-17.c考察静态局部变量的值f(inta)autointb=0;staticintc=3;b=b+1;c=c+1;return(a+b+c);main()inta=2,i;for(i=0;i3;i+)printf(“%d”,f(a);,运行结果:789,静态局部变量的声明:(1)分配在静态区,程序运行结束才释放存储单元。(与动态的区别)(2)仅开始时(编译时)划好房间赋初值一次(未赋初值时为0),以后每次调用函数时,变量不再赋值,直接使用前次操作的结果。(与动态的区别)(3)局部动态变量若未赋初值,其值是不确定的,所分配的存储单元是不固定的;而局部静态变量未赋初值,编译时赋其值为0(字符型变量的值为0),所分配的存储单元是固定的。(4)静态局部变量在函数调用结束后虽存在,但其它函数不能引用它。,使用局部静态变量有如下几种情况(1)需要保留上一次调用结束时的值例T8-18.c打印15的阶乘值intfac(intn)staticintf=1;f=f*n;return(f);main()inti;for(i=1;i=5;i+)printf(“%d!=%dn”,i,fac(i);返回(2)初始化后变量只被引用而不改变其值,则用静态局部变量较方便,以免每次调用都要赋初值。缺点:从程序运行开始到结束一直占用内存,这样会浪费系统资源。,问题:1.将static改为auto2.其它函数能否使用局部静态变量?,8.9.4register变量简介:cpu构造、degug演示、CPU和内存之间数据交换及速度、CacheCPU内部有寄存器组可用来存放数据,若把数据声明为寄存器类型,则将该类型的数据暂存放在寄存器中,其优点在于:减少数据与内存之间的交换频率,提高程序的效率和速度。,例T8.19.c使用寄存器变量intfac(intn)registerinti,f=1;for(i=1;i=n;i+)(思考,和staticf在程序上的区别)f=f*i;return(f);main()inti;for(i=1;i=5;i+)printf(“%d!=%dn”,i,fac(i);好处:n=10000000,运行结果:1!=12!=23!=64!=245!=120,例:C74-08.Cmain()registerinttemp,i;for(i=0;i=10000;i+)for(temp=0;temp=30000;temp+);printf(okn);,9-4变量的存储类型与作用域(续),例:比较下面两个程序的运算速度。main()registerinttemp,i;for(i=0;i=30000;i+)for(temp=0;tempy?x:y;return(z);main()externA,B;/*等价于externintA,B*/printf(“%d”,max(A,B);intA=13,B=-8;,运行结果:13,2.在多文件的程序中声明外部变量当一个程序由多个文件组成时,要在一个文件中引用另一文件中的外部变量时,此时要用extern加以声明;若在两个文件中同时对同名的外部变量定义,则系统连接时将提示“重定义类型错”例:给定b值,输入a和m,求ab和am,例T8-21用extern将外部变量的作用域扩展到其它文件。#include“T8-21-1.c”intAmain()intpower(int);intb=3,c,d,m;printf(“enterthenumberaanditspowerm:n”);scanf(%d%d”,输入:33输出:3*3=93*3=27,8.9.6用static声明外部变量若使全局变量只限于定义它的文件中的函数引用,而不让其它文件中的函数引用,需要用static加以说明。(注意:此种说法只在项目方法中有效,而在文件包含中则不起作用),例T8-21-2.c#include“T8-21-3.c”staticintA;main()A=5;printf(“A1=%dn”,A);f1();printf(“A4=%dn”,A);例T8-21-3.cexternintA;f1()printf(“A2=%dn”,A);A=A*A;printf(“A3=%dn”,A);,说明:(1)在运行T8-21-2.c时,无论有无static,其结果均是:A1=5A2=5A3=25A4=25这是因为用文件包含的方法,相当把T8-21-3.c包含进T8-21-2.c中来,使其成为T8-21-2的一部分了.(2)若用项目的方法,在T8-21-2中去掉#include“T8-21-3.c”建立工程文件名,如:t8-21-4.prjT8-21-2T8-21-3此时若有static则编译指出:标识符A在T8-21-3.c中无定义,若无static结果同上.另:不管有无static,均是静态存储,只是作用域不同罢了,8.9.7关于变量的声明和定义函数:声明部分:对有关的标识符(变量,函数,结构体)的属性进行说明,对于函数,声明和定义区别明显,声明是函数原型,定义是函数本身,是一个独立的程序模块;声明部分出现的变量有两种情况:1.定义性声明:需建立存储空间,如inta;也称定义。2.引用性声明:不建立存储空间,如externA广义地讲,声明包括定义,但并非所有的声明都是定义;如:intA;既包含声明又包含定义;externA;只是声明,而无定义。约定:建立存储空间的声明称定义;不建立存储空间的声明称声明。,外部变量定义性声明:整个程序中只有一次,且在所有函数之外。系统为其分配存储空间,并且只能在此进行初始化。外部变量引用性声明:同一文件中可多次进行。为提前引用后面定义的外部变量,用extern作声明。可在函数之内也可在函数之外。不分配存储空间Static定义性声明变量:(1)局部变量用static定义性声明,分配的存储空间在程序执行期间始终存在,但作用域只限定义它的函数或分程序。(2)全局变量用static定义性声明,变量的作用域仅限本文件模块。auto,register,static是在定义变量的基础上加上这些关键字,不能单独作用。inta;statica;不对!,8.9.8存储类别小结在C中,定义数据需指出数据类型和存储类别。(1)作用域:变量在某个文件或函数范围内是有效的,则称该文件或函数是该变量的作用域。哪里能被引用,静态外部变量:只限本文件引用外部(非静态)变量:允许其它文件引用,全局变量,(2)变量在某一时刻是存在的,认为这一时刻属于该变量的生成期:空间还在不在?释放掉没有?*静态存储方式:编译时就分配存储空间的,(3)从变量存在的位置来分:(4)关于作用域和生成期的概念用图例说明变量的作用域和生成期的关系,内存中动态存储区,自动变量和形式参数,CPU中的寄存器,寄存器变量,文件file1.cinta;main()f2();f1();f1()autointb;f2();f2()staticintc;,b作用域,c作用域,a作用域,mainf2mainf1f2f1main,变量存储类别函数内函数外作用域存在性作用域存在性自动和寄存器变量静态局部变量静态外部变量(文件内)外部变量(所有文件),a生成期,b生成期,c生成期,作用域:变量在函数或整个文件范围内是有效性的,称该文件或函数是该变量的作用域。生成期:变量在某个时刻是存在的,则认为这一时刻是变量的生成期。,关于static,对局部变量和全局变量的作用不同局部变量:由动态变为静态全局变量:由大家都可以引用到只能本文件使用(但都是静态存储方式)用了static以后,作用域都是有限的:要么本函数使用(静态局部变量)要么本文件使用(静态全局变量),下节预告,指针(请各位同学先自行预习)内部函数外部函数、多文件程序运行、预处理(宏定义-第9章)请同学们自学!,8.10内部函数和外部函数函数能否被其它源文件中的函数调用,看其是内部还是外部函数8.10.1内部函数只能被本文件中其它函数所调用形式:static类型标识符函数名(形参表列)若是内部函数,其作用域仅限于定义它的所在文件。此时在其它的文件中可以有相同的函数名,它们相互之间互不干扰。,8.10.2外部函数能被其它文件中的函数所调用。形式:extern类型标识符函数名(形参表列)注意:extern可省,隐含时,系统认其为外部函数。例8.22有一个字符串,内有若干个字符,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现。(自行思考),8.11如何运行一个多文件的程序1.用turboC集成环境(1)项目方法建立项目文件名.prj,其中包含一个程序的各文件名,在项目菜单项中设立项目文件名运行项目文件,按F9(2)文件包含方法在主函数的头部将本程序各文件用#include“文件名.c”运行该程序,
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!