




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第6章函数与预处理命令张雪英C
语言程序设计第6章函数与预处理命令
6.1概述6.2函数的定义与调用6.3数组作函数参数6.4函数的嵌套调用和递归调用6.5局部变量和全局变量及其作用域6.6变量的存储类别及变量的生存期6.7编译预处理6.8多文件程序的调试方法6.1概述对于任何应用程序来说都是由若干个程序模块组成的,而每一个模块常用来实现一个特定的功能。在C语言中就是利用函数来实现模块功能的。学生成绩管理系统
成绩录入成绩查询成绩统计打印成绩单6.1概述①程序结构清晰,可读性好。②减少重复编码的工作量。③可多人共同编制一个大程序,缩短程序设计周期,提高程序设计和调试的效率。使用函数的好处……C程序源程序文件n函数1函数m……源程序文件1函数1函数n举例说明:intcube(intx)/*函数定义*/{return(x*x*x);}main(){intf,n;printf(“请输入一个数:");scanf("%d",&n);f=cube(n);printf("%d*%d*%d=%d\n",n,n,n,f);}【例6-1】求一个数n的立方被调函数主调函数⑴一个C源程序可以由一个或多个源程序文件组成。C编译系统在对C源程序进行编译时是以文件为单位进行的。⑵一个C源程序文件可以由一个或多个函数组成。所有函数都是独立的。主函数可以调用其它函数,其它函数可以相互调用、自我调用。⑶在一个C程序中,有且仅有一个主函数main。C程序的执行总是从main函数开始,调用其它函数后最终回到main函数,在main函数中结束整个程序的运行。说明:6.2.1函数的分类函数的分类:
从用户角度标准函数(库函数):由系统提供用户自定义函数:int
cube(intx)从函数形式无参函数:getchar()有参函数:int
cube(intx)库函数包括:--数学函数:#include"math.h"--字符和字符串函数:#include"string.h"#include"ctype.h"--输入/输出函数:#include"stdio.h"使用库函数应注意:1、函数功能;2、函数参数的数目和顺序,及各参数意义和类型;3、函数返回值意义和类型;4、需要使用的包含文件。6.2.2函数的定义函数定义的一般格式:
函数类型函数名(类型名形参1,…..){说明语句执行语句
}例:求两个数的最大值
intmax(intx,inty){intz;
z=(x>y)?x:y;return(z);}省略为int型如没有,则为无参函数函数的定义函数也可以这样定义,但不可这样定义:intmax(x,y)intx,y;{intz;z=x>y?x:y;return(z);}intmax(x,y){intx,y;……}或intmax(intx,y){……}
或intmax(x,y)intx,y,z;{……..}
√注意:函数体可以为空,但{}不能省略。这种函数叫空函数不能在函数体内再定义其他函数,即函数不能嵌套定义。⑴函数类型即定义函数时函数返回值的类型,若定义时不指定函数类型,则隐含int型。⑵函数名是标识符,不可省略。其的()不可省略⑶形式参数表列是用,分隔开的一组变量名。(4){}括起来的部分是函数体,{}不可省略。(5)形式参数中声明的形式参数,在函数体中不需要再说明,可直接使用。函数定义的说明:6.2.2函数的调用函数调用的一般形式:
函数名(实参表列);
-在C语言中,把函数调用作为一个表达式,因此凡是表达式可以出现的地方都可以出现函数调用。例:welcome();if(fabs(a)>max)max=fabs(a);m=max(c,max(a,b));intsum(){inti,t=0;for(i=1;i<=100;i++)t+=i;return(t);}main(){ints;s=sum();printf("%d\n",s);}intsum(intx){inti,t=0;for(i=1;i<=x;i++)t+=i;return(t);}main(){ints,a=100;s=sum(a);printf("%d\n",s);}【例6-2】求1~100的累加和。思考:两个程序有何不同函数的调用举例:main(){longs;intn;scanf(“%d”,&n);s=factor(n);printf("%d\n",s);}【例6-3】定义求阶乘的函数factor。函数的调用举例:longfactor(intx){longy=1;inti;for(i=1;i<=x;i++)y=y*i;return(y);}这个函数能单独执行吗??函数的调用说明:函数调用说明:--实参与形参个数相等,类型一致,按顺序对应
--实参表求值顺序,因系统而定(VC从右向左)voidmain(){inti=2,p;intf(inta,intb);p=f(i,++i);printf("%d",p);}intf(inta,intb){intc;if(a>b)c=1;elseif(a==b)c=0;elsec=-1;return(c);}程序运行结果:0形式参数与实际参数
--形式参数:定义函数时函数名后面括号中的变量名
--实际参数:调用函数时函数名后面括号中的表达式6.2.3函数的参数【例6-4】编一程序,将主函数中的两个变量的值传递给swap函数中的两个形参,交换两个形参的值。voidswap(intx,inty){intz;z=x;x=y;y=z; printf("\nx=%d,y=%d",x,y);}main(){inta=10,b=20;swap(a,b);printf("\na=%d,b=%d\n",a,b);}函数的参数程序输出结果:x=20,y=10a=10,b=20形式参数(形参)实际参数(实参)单向值传递【例6-4】编一程序,将主函数中的两个变量的值传递给swap函数中的两个形参,交换两个形参的值。有关函数参数说明:
形参、实参的说明:
--形参与实参类型一致,个数相同;若类型不一致,自动按形参类型转换--实参可以是常量、变量或表达式,但要求它们有确定的值--当函数被调用时才给形参分配内存单元。调用结束后,所占用的内存单元被释放。但实参单元仍保留并维持原值-----单向的值传递
--在VC中,实参的求值顺序是从右向左
--函数的返回值,以定义函数时声明的返回值为主。而不管return返回的是什么类型的数据
举例:s(intr){return3.14*r*r;}main(){intr,area;scanf("%d",&r);printf("%d\n",s(r));}程序运行情况如下:212?【例6-5】计算并输出圆的面积思考:若要得到单精度实型的圆面积,程序应如何修改6.2.4函数的声明函数的声明:
--变量要先定义后使用,函数也如此。
--如调用在前,定义在后,则需要声明函数声明的形式:
类型名函数名(参数类型说明列表);
数据类型:必须与定义函数时的函数类型一致参数列表:可以省略形参名,但形参的类型、次序和数目必须一致函数声明的例子:main(){floatadd(floatx,floaty);/*函数声明*/floata,b,c;scanf(“%f,%f”,&a,&b);c=add(a,b);printf(“c=%f\n",c);}floatadd(floatx,floaty){floatz;z=x+y;return(z);}【例6-6】函数声明的例子:函数的声明:在下列情况下,可以省略函数声明:
--当函数的返回值为整型或字符型时,如果在同一个文件中即定义函数,又调用该函数,则不论定义函数与调用函数在源程序中的位置关系如何,都可以省去函数声明。
--如果被调用函数的返回值不是整型或字符型,但函数定义和函数调用在同一个文件中,且函数定义在调用函数之前,则可以省去在调用函数中对被调用函数的声明。swap()函数voidswap(intx,inty){intz;z=x;x=y;y=z; printf("\nx=%d,y=%d",x,y);}main(){inta=10,b=20;swap(a,b);printf("\na=%d,b=%d\n",a,b);}max()函数main(){inta,b,c;a=10;b=-3;c=max(a,b);…..}intmax(intx,inty){intx;x=(x>y)?x:y;returnx;}
函数声明的例子:【例6-7】哥德巴赫猜想之一是任何一个大于5的偶数都可以表示为两个素数之和。验证这一论断输入n的值for(a=6;a<=n;a+=2)for(b=3;b<=a/2;b+=2)b是素数?TFc=a-bc是素数?TF输出:a、b、c的值break;#include"math.h"intprime(intn);main(){inta,b,c,n;scanf("%d",&n);for(a=6;a<=n;a+=2)for(b=3;b<=a/2;b+=2) if(prime(b)){c=a-b;if(prime(c)){printf("%d=%d+%d\n",a,b,c);break;}}}程序如下:/*穷举法判断素数*/intprime(intn){inti,leap=1;for(i=2;i<=sqrt(n);i++)if(n%i==0){leap=0;break;}returnleap;}6.2.5函数的返回:从函数返回的两种方法:
--用return语句从被调函数中退出,返回调用它的程序中(也称为主调函数)
--被调函数中如没有return语句,则执行到被调函数最外面的}
,返回主调函数。return的双重作用
--控制程序从被调函数中退出,返回到主调函数中继续执行
--从被调函数向主调函数返回一个值函数的返回:intmax(intx,inty)
{
intz;
if(x>y)
z=x;
elsez=y;
return(z);}返回整型函数值返回不确定的函数值return;无返回语句在此返回函数的返回值:返回值规定:
--函数除去void
类型之外,均有一个返回值,返回值的类型就是在定义函数时说明的函数类型
--当返回值类型为int
型时,在定义函数时可省去函数的数据类型定义说明
--对于返回值的类型为非整型的函数,在定义函数时,必须明确地给出函数的数据类型说明返回语句的格式:
return;
或:return(表达式);6.3.1数组作函数参数数组名表示数组在内存中的起始地址例:inta[5];a:数组在内存中的起始地址,是常量
a[i]:数组元素a[0]a[1]a[2]a[3]a[4]数组作函数参数有两种情况:
--数组元素作函数参数(单向的值传递)
--数组名作函数参数(地址传递)数组元素作函数参数举例:voidswap(intx,inty){intz;z=x;x=y;y=z; }main(){inta[2]={1,2};swap(a[0],a[1]);printf("\na[0]=%d,a[1]=%d\n",a[0],a[1]);}【例6-8】数组元素作函数参数:12a调用前a[0]a[1]12a调用a[0]a[1]12xy21xy交换12a返回数组元素作参数:值传递数组名作函数参数数组名作函数参数---地址传递将数组在内存中的地址作为参数传递给形参特点:
--形参与实参占用同样的存储单元
--“双向”传递
--实参和形参必须是地址常量或变量
--实参和形参类型应一致(维数相同、元素类型相同)--一维形参数组大小可不指定,多维数组则只可省略第一维的大小数组名作函数参数举例:voidswap(intx[]){intz;z=x[0];x[0]=x[1];x[1]=z; }main(){inta[2]={1,2};swap(a);printf("\na[0]=%d,a[1]=%d\n",a[0],a[1]);}【例6-9】数组名作函数参数:12a调用前12ax调用21ax交换21a返回数组名作参数:地址传递数组名作函数参数举例:voidsort(intx[],intn){inti,j,k,t;for(i=0;i<n-1;i++){k=i;for(j=i;j<n;j++)if(x[j]<x[k])k=j;if(k!=i){t=x[i];x[i]=x[k];x[k]=t;} }main(){inta[10],i;for(i=0;i<10;i++)scanf(“%d”,&a[i]);sort(a,10);for(i=0;i<10;i++)printf(“%5d”,a[i]);}【例6-10】数组的排序----选择交换法排序:数组名作函数参数举例:floataverage(floatarray[10]);voidmain(){floatscore[10],ave;inti;printf(“Input10scores:\n”);for(i=0;i<10;i++)scanf(“%f”,&score[i]);ave=average(score);printf(“Averageif:%.2f”,ave);}floataverage(floatarray[10]){inti;floataver,sum=0;for(i=0;i<10;i++)sum=sum+array[i]);aver=sum/10;returnaver;}【例6-11】求学生成绩的平均值:..2109562312….….88scorearray实参用数组名形参用数组定义
floatarray[]数组名作函数参数举例:intmax_value(intarray[3][4]){inti,j,max;max=array[0][0];for(i=0;i<3;i++)for(j=0;j<4;j++)if(array[i][j]>max)max=array[i][j];returnmax;}voidmain(){inta[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}};printf(“max=%d\n”,max_value(a));}【例6-12】求二维数组中最大元素值:多维形参数组第一维维数可省略,第二维必须相同
intarray[][4]6.4.1函数的嵌套调用:C规定,函数定义不可嵌套,但可以嵌套调用函数
main函数{……
……
调用函数A;
……}函数A{…………
调用函数B;
……}函数B{……………………}调用调用返回返回函数嵌套调用举例:intdif(intx,inty,intz);intmax(intx,inty,intz);intmin(intx,inty,intz);voidmain(){inta,b,c,d;
对a,b,c赋值d=dif(a,b,c);printf(“max-min=%d\n”,d);}【例6-13】求三个数中最大数与最小数的差值:intmin(intx,inty,intz){intr;r=x<y?x:y;return(r<z?r:z);}intmax(intx,inty,intz){intr;r=x>y?x:y;return(r>z?r:z);}intdif(intx,inty,intz){returnmax(x,y,z)-min(x,y,z);}6.4.2函数的递归调用递归调用的概念:
--一个函数直接或间接地调用了它本身,就称为函数的递归调用。递归函数:在函数体内调用该函数本身例:intsub(intx){inty,z;…..if(…..)z=sub(y);else{…..}return;}直接调用sub函数本身递归函数的执行过程:思路:以求4的阶乘为例:4!=4*3!,3!=3*2!,2!=2*1!,1!=1,0!=1。递归结束条件:当n=1或n=0时,n!=1。递归公式:n!=1(n=0,1)n×(n-1)!(n>1)【例6-14】编一递归函数求n!:递归调用过程
回推main()fact(4)fact(3)fact(2)fact(1){{{{{……………
y=fact(4);f=4*fact(3);f=3*fact(2);f=2*fact(1);f=1;
……………return24return6return2return1}}}}}
递推
#include“stdio.h”main(){intn,l;scanf(“%d”,&n);l=fact(n);printf(“%d!=%d”,n,l);}intfact(intx){ints;if(x==1)s=1;elses=x*fact(x-1);returns;}程序如下:编制递归函数的方法:用递归方法解决问题必须满足三个条件:
--可以把要解决的问题转化为一个新问题,而这个新的问题的解决方法与原来的解决方法相同,只是处理的对象有规律地递增或递减
--可以应用这个转化过程使问题得到解决
--必须要有一个明确的结束递归的条件编写递归程序的方法:
--建立递归模型
--找出递归结束条件递归函数举例:xn=1(n=0)x×xn-1
(n>0)【例6-15】编一递归函数求xn:程序如下:longxn(intx,intn){longf=0;if(n<0)printf("n<0,dataerror!\n");elseif(n==0)f=1;elsef=x*xn(x,n-1);return(f);}main(){intn,x;longy;scanf("%d,%d",&x,&n);y=xn(x,n);printf("%ld\n",y);}程序运行情况如下:2,101024递归函数举例:【例6-16】编一递归函数求整数n的八进制数形式:程序如下:voiddtoo(intx){intm;m=x%8;x=x/8;if(x!=0)dtoo(x);printf(“%d”,m);}main(){intn;scanf("%d",&n);printf("%d=(",n);dtoo(n);printf(")8\n");}程序运行情况如下:1561315613=(36375)8递归函数举例:【例6-17】5个人坐一起,问第5个人多少岁?他说比第4个人大2岁,问第4个人多少岁?他说比第3个人大2岁。问第3个人多少岁?他说比第2个人大2岁。问第1个人多少岁?他说10岁。请问第5个人多大?intage(intn){intc;if(n==1)c=10;elsec=age(n-1)+2;returnc;}main(){printf(“%d\n“,age(5));}6.5变量的作用域与存储方式:voidf1(){intt=2;a*=t;b/=t;}main(){inta,b;scanf(“%d,%d”,&a,&b);f1();printf(“a=%d,b=%d\n”,a,b);}【例6-18】分析程序的运行结果:编译时,会出现错误信息提示:Undefinedsymbol‘a’和Undefinedsymbol‘b’。为什么?6.5.1变量的作用域概念:变量的作用域是指变量的有效使用范围
char型
int型
float型
double型总结:数据类型决定为变量分配的内存单元的长度,数据的存放形式。(从程序设计角度看,决定了可以表示的数的范围)问题:变量的有效作用范围如何?6.5.1变量的作用域:分类:全局变量、局部变量
局部变量在一个函数内部定义的变量,它只在本函数范围内有效,在此函数外不能使用的变量,又称内部变量主函数中定义的变量也是局部变量,只在主函数中有效不同函数中可以使用相同名字的局部变量,它们代表不同的对象,互不干扰;形参也属于局部变量;在一个函数内部的复合语句中定义的变量是局部变量,且只在本复合语句中有效。 变量的作用域:floatf1(inta)/*函数f1*/{intb,c;………}charf2(intx,inty)/*函数f2*/{inti,j;……}main()/*主函数*/{intm,n;………{inta,b;a=10;b=20;}}变量的作用域:
全局变量(又称外部变量)在一个函数之外定义的变量,称全局变量(全程变量或外部变量),其有效作用范围为从定义变量的位置开始到本源文件结束。全局变量可以为本文件中其他函数共用。
全局变量的作用:增加函数间数据联系的渠道
只有必要时(需要它传递数据时)才使用全局变量它占用存储单元时间长,在程序运行全过程中都占存储单元它使函数的通用性降低了,使用全局变量过多,会降低程序的清晰性变量的作用域:若在同一个源文件中,外部变量和局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用inta=3,b=5;/*a、b为全局变量*/max(inta,intb)/*a、b为形式参数,为局部变量*/{intc;c=a>b?a:b;return(c);}main(){inta=8;printf(“%d”,max(a,b));}6.6变量的存储方式:变量的作用域:从变量的作用范围来划分变量的存储方式:从变量的生存期来划分变量的存储方式:动态存储、静态存储
静态存储:在程序运行期间分配固定的存储空间,一直到程序运行结束为止。占静态存储区分配动态存储:在程序运行期间根据需要进行动态的分配存储空间,一旦需要结束,则立刻释放占据的内存空间。占动态存储区存放变量的存储类别:autostaticexternregister6.6.1auto变量:变量说明的一般形式:
存储类别数据类型变量名1,变量名2…;例:autointa,b;staticfloatx;auto变量:
自动变量是最常见的一类变量说明符“auto”可以省略。按照这种默认的规定,以前所使用的全部变量都是自动变量。6.6.2auto变量:auto变量:
自动变量必须在一个函数体的内部,形参也是自动变量。自动变量属动态存储方式(类别),占动态存储区空间,函数调用结束后即释放。自动变量的作用域是在所说明的函数内部,实质上是一个函数内部的局部变量。只有在函数被调用时才存在,从函数中返回时即消失,它们的值也仅限于说明它的函数,在其他的函数中不能存取。由于自动变量具有局部性,所以在两个不同函数中可以分别使用同名的变量而互不影响。变量的存储方式举例:main()/*主函数*/{intx=1;voidf1(void),f2(int);f1();f2(x);printf(“x=%d\n,”x);}voidf1(void){intx=3;printf(“x=%d\n,”x);}voidf2(intx){printf(“x=%d\n,”++x);}【例6-19】分析程序的运行结果:6.6.2变量的存储方式—静态局部变量:static变量:静态局部变量、静态外部变量
静态局部变量用“static”进行声明例:main(){staticinta;
intb;….}静态局部变量属静态存储类别,占静态存储区,在程序整个运行期间都不释放。静态局部变量是在编译时赋初值,即只赋初值一次,以后每次调用函数时不再重新赋初值而只保留上次函数调用结束时的值。6.6.2静态局部变量:static变量:静态局部变量、静态外部变量
静态局部变量与auto变量的区别:静态局部变量在每次调用的过程中能够保持数据的连续性(即保留上次函数调用结束时的值);而自动变量不能。若在定义static变量时未赋初值,其初值为0(对数据型变量)或空字符(对字符变量);而对auto自动变量来说,其初值不确定。变量的存储方式举例:main(){voidinc1(),inc2();inc1();inc1();inc1();inc2();inc2();inc2();}voidinc1(){intx=0;x++;printf(“inc1x=%d\n,”x);}voidinc2(){staticintx=0;x++;printf(“inc2x=%d\n,”x);}【例6-20】分析程序的运行结果:注意:当多次调用函数时往往弄不清静态局部变量当前值是什么,因此,如不必要,不要多用静态局部变量变量的存储方式举例:intf(inta){autointb=0;staticintc=3;b=b+1;c=c+1;returna+b+c;}main(){inta=2,i;for(i=0;i<3;i++)printf(“%d”,f(a));}【例6-21】分析静态局部变量的值:第一次调用开始03bc第一次调用结束1404第二次调用开始7896.6.2静态外部变量:static变量:静态局部变量、静态外部变量
静态外部变量:在定义外部变量时加一个static声明后,此变量就只能被本文件引用,而不能被其他文件引用,这样的变量叫静态外部变量例:inta;/*外部变量*/staticintb;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 单位蔬菜供应合同范本
- 合同范本其他事项
- 合同范本软件画画
- 卷帘窗帘购销合同范例
- 2025年耐磨合金铸铁项目建议书
- 新西兰蜂蜜采购合同范本
- 水果购销合同范本
- 家具设计合同范本
- 单位车辆定点维修合同范本
- 医院租赁合同范本
- 随机交易策略(TB版)
- 《绿色建筑设计原理》课件
- 中医馆装修合同范本
- 1.1 锐角三角函数(第1课时) 课件 2024-2025学年北师大版九年级数学下册
- 椎管打骨水泥后的护理
- 学习与科技的融合主题班会
- 《直播销售》课件-项目一 认识直播与直播销售
- 2025年南京科技职业学院高职单招数学历年(2016-2024)频考点试题含答案解析
- 2025-2030年中国航空配餐行业市场发展现状及投资前景规划研究报告
- 新课标背景下的跨学科学习内涵、设置逻辑与实践原则
- 母婴分离产妇的护理
评论
0/150
提交评论