C语言程序设计(微课版)课件 第六章 函数_第1页
C语言程序设计(微课版)课件 第六章 函数_第2页
C语言程序设计(微课版)课件 第六章 函数_第3页
C语言程序设计(微课版)课件 第六章 函数_第4页
C语言程序设计(微课版)课件 第六章 函数_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C语言程序设计

第一章程序设计基础两数求最大值的例子:main() /*主函数*/{ /*main函数体开始*/inta,b,c; /*声明部分定义变量*/scanf(“%d,%d”,&a,&b);

c=max(a,b);/*调用max,将调用结果赋给c*/printf(“max=%d”,c);} /*main函数体结束*/intmax(intx,inty) /*计算两数中较大数的函数*/{ /*max函数体开始*/intz; /*声明部分,定义变量*/if(x>y)z=x;elsez=y;returnz; /*将z值返回,通过max带回调用处*/} /*max函数体结束*/程序设计的艺术程序设计有两大最高级的艺术算法设计艺术结构设计艺术函数(function)是结构设计的最基本单位“一个程序应该是轻灵自由的,它的子过程(函数)就象串在一根线上的珍珠。”GeoffreyJames的《编程之道》数学函数(1)自变量因变量函数规则函数结果(返回值)函数名参数

C语言程序设计

第一章程序设计基础两数求最大值的例子:main() /*主函数*/{ /*main函数体开始*/inta,b,c; /*声明部分定义变量*/scanf(“%d,%d”,&a,&b);

c=max(a,b);/*调用max,将调用结果赋给c*/printf(“max=%d”,c);} /*main函数体结束*/intmax(intx,inty) /*计算两数中较大数的函数*/{ /*max函数体开始*/intz; /*声明部分,定义变量*/if(x>y)z=x;elsez=y;returnz; /*将z值返回,通过max带回调用处*/} /*max函数体结束*/第六章函数6.1.1

概述模块化程序设计一个C程序可由一个主函数(main()函数)和若干个功能函数共同构成基本思想:把程序所实现的不同功能,分别写成不同的功能函数,用到哪个功能就调用哪个.各函数之间的调用关系如下:由主函数调用其他函数,其他函数也可以互相调用,但不能调用主函数。同一个函数可以被一个或多个函数调用任意多次。特点:各模块相对独立、功能单一、结构清晰、接口简单符合结构化设计思想,便于设计,调试和扩充控制了程序设计的复杂性提高程序的可靠性缩短开发周期避免程序开发的重复劳动易于维护和功能扩充C各函数之间的关系一个C程序由一个或多个源程序文件组成一个源程序文件由一个或多个函数组成;源程序文件是编译单位C程序的执行总是从main函数开始,调用了其它函数后返回main函数,在main函数中结束整个程序的运行。调用者称主调函数,被调用者称被调函数所有函数都是平行的,不能嵌套定义.函数间可以互相调用,但是不能调用主函数.C程序结构源程序文件1预编译命令说明部分执行部分函数1函数n源程序文件i源程序文件nC程序函数分类从用户角度标准函数(库函数):由系统提供用户自定义函数从有无返回值有返回值无返回值从函数形式无参函数有参函数6.2函数定义(definition)返回值类型

函数名(类型参数1,类型参数2,……

)

{

函数体

return

表达式;

}说明:C语言规定不能在函数内部再定义其它函数,即不能嵌套定义。当函数执行到return语句时,程序流程就中止函数的执行,返回到主调函数调用它的地方函数内部定义的变量只能自己使用,称内部变量。

参数表里形参的变量也是属于内部变量函数的返回值是通过函数中的return

语句获得的。

C语言程序设计

第一章程序设计基础两数求最大值的例子:main() /*主函数*/{ /*main函数体开始*/inta,b,c; /*声明部分定义变量*/scanf(“%d,%d”,&a,&b);

c=max(a,b);/*调用max,将调用结果赋给c*/printf(“max=%d”,c);} /*main函数体结束*/intmax(intx,inty) /*计算两数中较大数的函数*/{ /*max函数体开始*/intz; /*声明部分,定义变量*/if(x>y)z=x;elsez=y;returnz; /*将z值返回,通过max带回调用处*/} /*max函数体结束*/计算两个整数的平均数/*

函数功能:计算平均数函数入口参数:整型x,存储第一个运算数整型y,存储第二个运算数函数返回值:平均数*/intAverage(intx,inty){

intresult; result=(x+y)/2;

returnresult;}6.2.2

函数的参数和返回值函数的形参和实参实际参数:在主调函数中去调用一个函数时,函数名后面括弧中的参数

形式参数:定义函数时函数名后面括弧中的变量说明:在定义函数中指定的形参,在未出现函数调用时,形参并不占内存中的存储单元,只有发生函数调用时,形参才被分配内存单元。调用结束后,形参所占的内存单元也被释放实参可以是常量,变量或表达式。调用时,实参的值必须确定实参和形参的类型应相同或者赋值兼容实参变量对形参变量的数据传递是单向值传递。下一页c=max(a,b);(main函数)(max函数)intmax(intx,inty){intz;z=x>y?x:y;return(z);}main(){inta,b,c;scanf("%d,%d",&a,&b);c=max(a,b);printf("Maxis%d",c);}intmax(intx,inty){intz;z=x>y?x:y;return(z);}形参实参上一页711x:y:调用前:调用结束:711x:y:例交换两个数#include<stdio.h>voidswap(inta,intb){inttemp;temp=a;a=b;b=temp;}main(){intx=7,y=11;printf("x=%d,\ty=%d\n",x,y);printf("swapped:\n");

swap(x,y);printf("x=%d,\ty=%d\n",x,y);}调用:711a:b:711x:y:swap:711x:y:117a:b:temp§6.2.5数组作为函数参数1、一维数组元素作为函数参数(普通变量)一维数组中元素作为函数的实参,与同类型的简单变量作为实参效果一样,是单向的值传递,即数组元素的值传给形参,形参的改变不影响实参。

例:数组元素值能否交换?#include<stdio.h>

voidchange(intx,inty)

{intt;t=x;x=y;y=t;}

voidmain()

{inta[2];scanf("%d,%d",&a[0],&a[1]);change(a[0],a[1]);printf("%d,%d\n",a[0],a[1]);}例2、数组名作为函数参数(传递数组首地址)数组名作为函数参数,此时形参和实参都是数组名(或者是表示地址的指针变量,指针讲),传递的是整个数组,即形参数组和实参数组完全等同,是存放在同一空间的同一个数组。这样形参数组修改时,实参数组也同时被修改了。#include<stdio.h>voidchange(intb[]){ intt;t=b[0];b[0]=b[1];b[1]=t;}voidmain(){inta[2];scanf("%d,%d",&a[0],&a[1]);change(a);printf("%d,%d\n",a[0],a[1]);}例数组名作函数参数时要注意:形参中的数组要定义,并且要求与实参数组类型一致,但是形参数组的大小(即元素个数)在编译的时候不起任何作用,系统也不对数组大小进行检查,所以形参数组的元素个数可以省略,而由一个专门的参数传递元素个数。例数组元素与数组名作函数参数比较12a调用前a[0]a[1]12a调用a[0]a[1]12xy21xy交换12a返回#include<stdio.h>voidswap2(intx,inty){intz;z=x;x=y;y=z;}main(){inta[2]={1,2};

swap2(a[0],a[1]);printf("a[0]=%d\na[1]=%d\n",a[0],a[1]);}值传递12a调用前12ax调用21ax交换21a返回#include<stdio.h>voidswap2(intx[]){intz;z=x[0];x[0]=x[1];x[1]=z;}main(){inta[2]={1,2};

swap2(a);printf("a[0]=%d\na[1]=%d\n",a[0],a[1]);}地址传递例数组元素与数组名作函数参数比较例求学生的平均成绩#include<stdio.h>

floataverage(intstu[],intn);

voidmain(){intscore[10],i;floatave;printf("Input10scores:\n");for(i=0;i<10;i++)scanf("%d",&score[i]);ave=average(score,10);printf("Averageis:%.2f",ave);}floataverage(intstu[],intn){inti;floatave,total=0;for(i=0;i<n;i++)total+=stu[i];ave=total/n;returnave;}实参用数组名..2109score562312….….88stu2、函数的返回值:通过函数调用使得主调函数得到一个确定的值,就是函数返回值。函数返回值的类型和函数定义时的类型应该保持一致。函数的返回值是通过函数中的return语句获得。返回语句:形式:

return(表达式);

return表达式;

return;功能:使程序控制从被调用函数返回到调用函数中,同时把返值带给调用函数说明:一个函数中允许有多个return语句函数首部的所定义的函数类型应尽量与return返回值类型一致用void定义无返回值的函数,函数内应无return语句函数调用(call)有返回值时放到一个表达式中如:c=max(a,b);作为另一个函数调用的参数如

c=max(max(a,b),c);printf("%d\n",max(a,b));无返回值时函数调用表达式如:display(a,b);返回值例函数返回值类型转换max(floatx,floaty){floatz;z=x>y?x:y;return(z);}voidmain(){floata,b;intc;scanf("%f,%f",&a,&b);printf("%f,%f\n",a,b);c=max(a,b);printf("Maxis%d\n",c);}为了明确表示“不带回值”,可以给函数定义时用“void”定义。例无返回值函数

voidswap(intx,inty){inttemp;temp=x;x=y;y=temp;}函数声明和原型对被调用函数要求:库函数:#include<*.h>用户自定义函数:函数声明函数声明一般形式:函数类型函数名(形参类型1形参名1,..);

或函数类型函数名(形参类型1,形参类型2,…);作用:告诉编译系统函数类型、函数名及参数类型,以便检验函数定义与函数声明不同函数定义:定义函数的完整功能模块函数声明:有助于编译器进行函数类型、函数名及参数类型检查函数声明位置:所有函数定义之前或者主调函数中。main(){floata,b,c;scanf("%f,%f",&a,&b);

c=add(a,b);printf("sumis%f",c);}floatadd(floatx,floaty){floatz;z=x+y;return(z);}floatadd(float,float);注意

调用一个函数之前,先要对其返回值类型、函数名和参数进行声明(declare)有助于编译器进行类型检查floatadd(floatx,floaty);

/*functiondeclaration*/#include<stdio.h>main(){ inta=12; intb=24; ave=Average(a,b);

printf("Averageof%dand%dis%d.\n",a,b,ave);}intAverage(intx,inty){

intresult; result=(x+y)/2;

returnresult;}函数定义写在主调函数前#include<stdio.h>main(){

inta=12;

intb=24; ave=Average(a,b);

printf("Averageof%dand%dis%d.\n",a,b,ave);}intAverage(intx,inty){

intresult; result=(x+y)/2;

returnresult;}函数定义写在主调函数后intAverage(intx,inty);/*声明Average()函数*/intAverage(intx,inty);/*声明Average()函数*/例函数说明举例main(){floata,b;intc;scanf("%f,%f",&a,&b);c=max(a,b);printf("Maxis%d\n",c);}max(floatx,floaty){floatz;z=x>y?x:y;return(z);}被调函数类型为整形,可以在函数调用前不必做函数声明,系统自动用:intmax();来检查只不过无法对参数的类型做检查。6.4

函数的调用调用一般形式函数名(实参表);说明:实参与形参个数相等,类型一致,按顺序一一对应实参表求值顺序,因系统而定(TurboC,C++自右向左)intf(inta,intb){intc;if(a>b)c=1;elseif(a==b)c=0;elsec=-1;return(c);}main(){inti=2,p;p=f(i,++i);

printf("%d\n",p);}例参数求值顺序运行结果:0调用方式函数语句:例printf(“Hello,World!\n”);函数表达式:例m=max(a,b)*2;函数参数:例printf(“%d”,max(a,b));m=max(a,max(b,c));课堂作业:写出如下程序输出结果:#include<stdio.h>intfun(intn1,intn2){if(n1>n2)returnn1;returnn2;}voidmain(){intn1=2,n2=3;printf(“result=%d\n”,fun(n1++,n2+=2));printf(“result=%d\n”,fun(n2+n1,n1=1));}6.2.6

函数的嵌套与递归调用嵌套调用C规定:函数定义不可嵌套,但可以嵌套调用函数main(){……a();}a

函数{b();…return;}b函数{……return;}①③④⑤⑥⑦②例输入三个数,求其中最大数和最小数的差值#include<stdio.h>

intdif(intx,inty,intz);intmax(intx,inty,intz);intmin(intx,inty,intz);voidmain(){inta,b,c,d;scanf("%d%d%d",&a,&b,&c);

d=dif(a,b,c);printf("Max-Min=%d\n",d);}intdif(intx,inty,intz){returnmax(x,y,z)-min(x,y,z);}intmax(intx,inty,intz){intr;r=x>y?x:y;return(r>z?r:z);}intmin(intx,inty,intz){intr;r=x<y?x:y;return(r<z?r:z);}main()调用函数dif输出结束dif函数max函数调用函数max调用函数minmin函数递归调用递归调用:C语言的函数调用允许直接或间接地调用该函数本身,称为函数的递归调用。递归调用函数的使用可以解决具有递归性质的问题。f()调f调f2调f1f1()f2()intf(intx){inty,z;……

z=f(y);…….return(2*z);}intf1(intx){inty,z;……

z=f2(y);…….return(2*z);}intf2(intt){inta,c;……

c=f1(a);…….return(3+c);}例:有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第3个人,又说比第2个人大2岁。问第2个人,说比第1个人大2岁。最后问第1个人,他说是10岁。问第5个人多大?age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10#include<stdio.h>intage(intn){intc;

if(n==1)c=10;elsec=age(n-1)+2;return(c);}main(){printf("%d",age(5));}注意:递归调用必须可以满足一定条件时结束递归调用,否则无限地递归调用将导致程序无法结束。例求n的阶乘#include<stdio.h>intfac(intn){intf;if(n<0)printf("n<0,dataerror!");elseif(n==0||n==1)f=1;elsef=fac(n-1)*n;return(f);}main(){intn,y;printf("Inputaintegernumber:");scanf("%d",&n);

y=fac(n);printf("%d!=%15d",n,y);}说明C编译系统对递归函数的调用次数没有限制。每调用函数一次,需在内存栈区分配空间,用于存放函数变量、返回值等信息,所以递归次数过多,可能引起栈溢出。递归是一种非常有效的数学方法,也是程序设计的重要算法。对于某些问题的处理,采用递归方法效果明显,但递归也需占用大量的时间和额外内存,在确定算法之前应综合考虑是否选用递归方法。intp=1,q=5;floatf1(inta){intb,c;…….}intf3(){…..}charc1,c2;charf2(intx,inty){inti,j;……}main(){intm,n;…….}局部变量与全局变量局部变量---内部变量定义:在函数内定义的变量(包括形参)或者在复合语句块内部定义的变量特点:并列函数模块各自定义的变量包括同名变量互不干扰当发生函数调用,进入函数模块时局部变量才分配内存,仅能由函数模块内操作语句访问,退出函数时释放内存,不再有效定义局部变量时其不会自动初始化,需要程序员指定初值floatf1(inta){intb,c;…….}charf2(intx,inty){inti,j;……}main(){intm,n;…….}a,b,c有效x,y,i,j有效m,n有效例复合语句中变量#defineN5main(){inti;inta[N]={1,2,3,4,5};for(i=0;i<N/2;i++)

{

inttemp; temp=a[i]; a[i]=a[N-i-1]; a[N-i-1]=temp;

}for(i=0;i<N;i++)printf("%d",a[i]);}例不同函数中同名变量main(){inta,b;a=3;b=4;printf("main:a=%d,b=%d\n",a,b);sub();printf("main:a=%d,b=%d\n",a,b);}voidsub(){inta,b;a=6;b=7;printf("sub:a=%d,b=%d\n",a,b);}变量的作用域:全局变量---外部变量定义:在所有函数之外定义的变量特点:在程序中从定义它的位置开始到整个程序结束都有效,它属于它所在的源文件,在某一函数中对全局变量所做的改变,也会影响其他函数中这个变量的值。从程序运行起就开辟内存空间,程序运行过程中可随时访问并一直有效,直到程序全部结束才释放内存使函数之间的数据交换更容易,也更高效但是并不推荐使用,尽量少用。因为谁都可以改写全局变量,所以很难确定是谁改写了它在定义点之前或在其他文件中引用,应该进行如下声明:extern类型名变量名;intp=1,q=5;floatf1(inta){intb,c;…….}intf3(){…..}charc1,c2;charf2(intx,inty){inti,j;……}main(){intm,n;…….}intp=1,q=5;floatf1(inta){intb,c;…….}intf3(){…..}charc1,c2;charf2(intx,inty){inti,j;……}main(){intm,n;…….}c1,c2的作用范围p,q的作用范围externcharc1,c2;externcharc1,c2;c1,c2的作用范围扩展后c1,c2的作用范围扩展后inta=6,b=10;max(inta,intb){intc;c=a>b?a:b;return(c);}main(){inta=15;printf(“max=%d”,max(a,b));}若外部变量与局部变量同名,则外部变量被屏蔽,仅内部变量有效intvs(intl,intw){externinth;intv;v=l*w*h;returnv;}voidmain(){externintw,h;intl=5;printf("v=%d",vs(l,w));}intl=3,w=4,h=5;变量的存储类别:指数据在内存中存储的方式即编译器为变量分配内存的方式,它决定变量的生存期动态存储方式:根据需要临时分配存储空间,离开即释放静态存储方式:在程序运行整个期间分配固定的存储空间不释放(全局变量)变量完整的定义格式:

[存储类型]

数据类型变量名;变量的存储类型auto-----自动型register-----寄存器型static------静态型extern-----外部型6.4

变量的存储类别及生命周期程序区静态存储区动态存储区形参、自动变量、函数调用的现场等全局变量、静态变量函数中的形参函数内定义的局部变量函数内复合语句定义的变量“自动”体现在:进入函数模块时自动申请内存,退出时自动释放

intf(inta){

autointb,c=3;}注意:关键字”auto”可省,隐含为”自动存储类别”,它属于动态存储方式.程序中大多数局部变量属于自动变量.auto变量:函数当中的局部变量,定义时使用auto或者没有指定存储类型时,称自动变量。等价于intb,c=3;寄存器变量(register)寄存器:CPU的内部容量很有限、但速度极快的存储器什么变量可定义为寄存器变量?只有局部自动变量和形参可以作为寄存器变量,其它(如全局变量)不行.使用频率比较高的变量声明为register,可以使程序更小、执行速度更快现代编译器有能力自动把普通变量优化为寄存器变量,并且可以忽略用户的指定,所以一般无需特别声明变量为registermain(){longintsum=0;floatave;

registerinti;

for(i=1;i<=2000;i++)sum+=i;ave=sum/2000.0;printf(“sum=%ld\n”,sum);printf(“ave=%f\n”,ave);}静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在程序整个运行期间都不释放.对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值.定义静态局部变量时不赋初值,编译时自动赋初值为0虽然静态局部变量在函数调用结束后仍然存在,但其它函数是不能引用它的.static变量:fun(inta){intb=0;

staticintc=0;b++;c=c+b;return(a+b+c);}main(){inta=2,i;for(i=0;i<3;i++)printf(“%d\n”,fun(a));}main(){voidincrement();increment();increment();increment();}voidincrement(){intx=0;x++;printf(“%d\n”,x);}例局部静态变量值具有可继承性运行结果:111main(){voidincrement();increment();increment();increment();}voidincrement(){staticintx=0;x++;printf(“%d\n”,x);}运行结果:1231.在一个文件内声明外部变量extern变量:intp=1,q=5;floatf1(inta){intb,c;…….}intf3(){…..}charc1,c2;charf2(intx,inty){inti,j;……}main(){intm,n;…….}c1,c2的作用范围p,q的作用范围externcharc1,c2;externcharc1,c2;c1,c2的作用范围扩展后c1,c2的作用范围扩展后intmax(intx,inty){intz;z=x>y?x:y;return(z);}main(){externintA,B;printf(“%d”,max(A,B));}intA=13,B=-8;2.在多文件的程序中声明外部变量extern变量:例引用其它文件中的外部变量intglobal;externfloatx;main(){intlocal; . . .}externintglobal;staticintnumber;func2(){ . . .}floatx;staticintnumber;func3(){externintglobal; . . .}file1.cfile2.cfile3.c6.5外部函数和内部函数1内部函数定义:如果一个函数只能被本文件中其它函数调用,称为内部函数(又称静态函数)。格式:static类型标识符函数名(形参表)例如:staticintfun(inta,intb){..….}作用:函数的作用域限于所在文件,不同文件中同名函数互不干扰,便于程序的局部化。2外部函数定义:如果一个函数允许被其它文件调用,称为外部函数。格式:extern类型标识符函数名(形参表)例如:externintfun(inta,intb){..….}intfun(inta,intb){..….}或

类型标识符函数名(形参表)或通常不加static标识符的函数都是外部函数。例文件file1.cinta;main(){…….…….f2();…….f1();…….}f1(){autointb;………f2();……..}f2(){staticintc;………}C作用域b作用域a作用域mainf2f1mainf1f2maina生存期:b生存期:c生存期:一、编译预处理的概念

预处理部分都是放在函数之外和程序的开始,它是程序编译时首先要做的工作,编译系统对源程序中的预处理部分做处理,结束后才进入源程序的编译.二、主要预处理种类⑴文件包含(#include);⑵宏定义(#define);⑶条件编译6.6编译预处理

6.6.1文件包含命令

“文件包含”:是指一个源文件可以将另外一个源文件的全部内容包含进来。C语言提供#include命令来实现“文件包含”的操作,其一般形式为:

#include“文件名”

#include<文件名>或作用:可以节省程序设计人员的重复劳动在使用编译预处理#include命令时,需要注意的几个问题如下:(1) 一个#include命令只能指定一个被包含的文件,如果要包含n个文件,要用n个#include命令(2) 在一个被包含文件中又可以包含另一个文件,文件包含可以嵌套使用,即被包括的文件中还可以使用#include语句。(3) 在#include命令中,文件名可以用双引号或尖括号

二者区别:#include“文件名”直接到系统指定的标准目录(存放库函数文件)中去查找(标准方式)。#include<文件名>先在用户当前源程序文件所在工作目录中去查找,若找不到再到指定的标准目录中去查找

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论