新编-C语言培训教材课件第5章_第1页
新编-C语言培训教材课件第5章_第2页
新编-C语言培训教材课件第5章_第3页
新编-C语言培训教材课件第5章_第4页
新编-C语言培训教材课件第5章_第5页
已阅读5页,还剩97页未读 继续免费阅读

下载本文档

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

文档简介

第5章函数2019年3月1第5章函数2019年3月1主要内容

5.1概述5.2函数的定义与调用5.3数组作函数参数5.4函数的嵌套调用和递归调用5.5局部变量和全局变量及其作用域5.6变量的存储类别及变量的生存期5.7函数的存储分类2019年3月2主要内容5.1概述2019年3月25.1概述①程序结构清晰,可读性好。②减少重复编码的工作量。③可多人共同编制一个大程序,缩短程序设计周期,提高程序设计和调试的效率。使用函数的好处……C程序源程序文件n函数1函数m……源程序文件1函数1函数n2019年3月35.1概述①程序结构清晰,可读性好。使用函数的……C程序【例5.1】求一个整数的立方。intcube(intx)

/*函数定义*/{return(x*x*x);}main(){intf,a;printf("\nEnteranintegernumber:");scanf("%d",&a);f=cube(a);

printf("%d*%d*%d=%d\n",a,a,a,f);}程序运行情况如下:Enteranintegernumber:22*2*2=8函数调用程序的执行总是从main函数开始2019年3月4【例5.1】求一个整数的立方。intcube(intx⑴一个C源程序可以由一个或多个源程序文件组成。C编译系统在对C源程序进行编译时是以文件为单位进行的。⑵一个C源程序文件可以由一个或多个函数组成。所有函数都是独立的。主函数可以调用其它函数,其它函数可以相互调用。⑶在一个C程序中,有且仅有一个主函数main。C程序的执行总是从main函数开始,调用其它函数后最终回到main函数,在main函数中结束整个程序的运行。说明2019年3月5⑴一个C源程序可以由一个或多个源程序文件组成。C编译系统在⑷函数的种类从函数定义形式分:①有参函数:在主调(用)函数和被调(用)函数之间通过参数进行数据传递,如:

intcube(intx){…}

②无参函数:如:getchar()在调用无参函数时,主调函数不需要将数据传递给无参函数。从使用的角度看:①标准函数(库函数)库函数是由系统提供的。如:getchar()、sin(x)等。在程序中可以直接调用它们。附录3列出了C的部分库函数。②用户自定义函数。如:例5.1中的cube函数。2019年3月6⑷函数的种类从函数定义形式分:从使用的角度看:2019年3【例5.2】无参函数的定义与调用。voidwelcome(){printf("*********************************\n");printf("WelcometoChina\n");printf("*********************************\n");}main(){welcome();}程序的输出结果如下:*********************************

WelcometoChina*********************************2019年3月7【例5.2】无参函数的定义与调用。voidwelcome5.2.1函数的定义函数定义的一般形式函数类型函数名(类型名形式参数1,…

){说明语句

执行语句}例如:求两个数的最大值。

int

max(intx,inty){intz;z=x>y?x:y;return(z);}类型省略时默认为int类型没有形式参数为无参函数

2019年3月85.2.1函数的定义函数定义的一般形式函数类型函数名(类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;{z=x>y?x:y;return(z);}花括号中也可以为空,这种函数叫空函数。不能在函数体内定义其他函数,即函数不能嵌套定义。形参也可以这样定义如下定义都是错误的

√2019年3月9intmax(x,y)intmax(x,y)或花括号中也函数名(实参表列)在C语言中,把函数调用也作为一个表达式。因此凡是表达式可以出现的地方都可以出现函数调用。例如:①welcome();

②if(iabs(a)>max)max=iabs(a);

③m=max(c,max(a,b));5.2.2函数的调用函数调用的一般形式:2019年3月10函数名(实参表列)在C语言中,把函数调用也作为一个表达式。因intsum100(){inti,t=0;for(i=1;i<=100;i++)t+=i;return(t);}main(){ints;s=sum100();printf("%d\n",s);}程序输出结果:5050intsum(intx){inti,t=0;for(i=1;i<=x;i++)t+=i;return(t);}main(){ints;s=sum(100);printf("%d\n",s);}【例5.3】求1~100的累加和。思考:两个程序有何不同程序输出结果:5050?2019年3月11intsum100()程序输出结果:intsum(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);}5.2.3函数参数与函数的返回值1.函数的形式参数与实际参数程序输出结果:x=20,y=10a=10,b=20形式参数(形参)实际参数(实参)【例5.4】编一程序,将主函数中的两个变量的值传递给swap函数中的两个形参,交换两个形参的值。单向值传递2019年3月12voidswap(intx,inty)5.2.3有关形参和实参的说明:

①当函数被调用时才给形参分配内存单元。调用结束,所占内存被释放。②实参可以是常量、变量或表达式,但要求它们有确定的值。③实参与形参类型要一致,字符型与整型可以兼容。④实参与形参的个数必须相等。在函数调用时,实参的值赋给与之相对应的形参。“单向值传递”。注意:在TC中,实参的求值顺序是从右到左。2019年3月13有关形参和实参的说明:①当函数被调用时才给形参分配内存单【例5.5】函数调用中实参的求值顺序。voidfun(inta,intb){printf("a=%d,b=%d\n",a,b);}main(){intm=5;fun(3+m,m++);}程序输出结果:a=9,b=52019年3月14【例5.5】函数调用中实参的求值顺序。voidfun(i2.函数的类型与函数的返回值说明:①函数的类型决定了函数返回值的类型。若省略函数的类型,系统默认其为int型。②无返回值的函数应将其类型定义为void(空)类型。⑴函数的类型【例5.6】输出两个数中的大数。max(intx,inty){intz;z=x>y?x:y;return(z);/*返回z的值*/}main(){inta,b,c;scanf("%d,%d",&a,&b);c=max(a,b);printf("maxis%d\n",c);}2019年3月152.函数的类型与函数的返回值说明:⑴函数的类型【例5.6】函数的返回值是通过return语句带回到主调函数的功能:终止函数的运行,返回主调函数,若有返回值,将返回值带回主调函数。说明:①若函数没有返回值,return语句可以省略。②return语句中的表达式类型一般应和函数的类型一致,如果不一致,系统自动将表达式类型转换为函数类型。⑵函数的返回值return语句格式:return(表达式);

或return表达式;或return;2019年3月16函数的返回值是通过return语句带回到主调函数的功能:终止【例5.8】计算并输出圆的面积。s(intr){return3.14*r*r;}main(){intr,area;scanf("%d",&r);printf("%d\n",s(r));}自动转换为int型思考:若要得到单精度实型的圆面积,程序应如何修改程序运行情况如下:212?2019年3月17【例5.8】计算并输出圆的面积。s(intr)自动转换为i

5.2.4对被调函数的声明和函数原型变量要先定义后使用,函数也如此。即被调函数的定义要出现在主调函数的定义之前。如swap函数:允许整型函数(且参数也是整型)的定义出现在主调函数之后。如max函数:如果非整型函数在主调函数之后定义,则应在主调函数中或主调函数之前对被调函数进行声明。voidswap(intx,inty){…}main(){…swap(a,b);}main(){…c=max(a,b);}max(intx,inty){…}2019年3月185.2.4对被调函数的声明和函数原型变量要先定义后使用对被调函数进行声明的一般形式

函数类型函数名(参数类型1

参数名1,…);或函数类型函数名(参数类型1,参数类型2,…);思考:以下哪种情况需要在主调函数中对被调函数声明被调函数定义在前,主调函数定义在后。主调函数定义在前,被调函数定义在后。第二种形式省略了参数名,此种形式也称为函数的原型。?2019年3月19对被调函数进行声明的一般形式函数类型函数名(参main(){voidcalc(floatx,floaty,charopr);

floata,b;charopr;printf("\nInputexpression:");scanf("%f%c%f",&a,&opr,&b);calc(a,b,opr);}voidcalc(floatx,floaty,charopr){switch(opr){case'+':printf("%5.2f%c%5.2f=%6.2f\n",x,opr,y,x+y);return;case'-':printf("%5.2f%c%5.2f=%6.2f\n",x,opr,y,x-y);return;case'*':printf("%5.2f%c%5.2f=%6.2f\n",x,opr,y,x*y);return;case'/':printf("%5.2f%c%5.2f=%6.2f\n",x,opr,y,x/y);return;default:printf("Operatorerr!\n");}}对被调函数的声明【例5.9】计算并输出两个数的和、差、积、商。2019年3月20main()对被调函数的声明【例5.9】计算并输出两个数的5.3数组作函数参数5.3.1一维数组元素作函数参数main(){inta[5],i,m;for(i=0;i<5;i++)scanf("%d",&a[i]);m=a[0];for(i=1;i<5;i++)m=min(m,a[i]);printf("%d\n",m);}【例5.11】求5个数中的最小值。intmin(intx,inty){return(x<y?x:y);}用打擂台方法求最小值。m相当于擂主2019年3月215.3数组作函数参数5.3.1一维数组元素作函数参数ma5.3.2一维数组名作函数参数数组名表示数组在内存中的起始地址。例如:数组a在内存中从2000地址开始存放,则a的值为2000。2000是地址值,是指针类型的数据(后面将介绍指针类型),不能把它看成是整型或其他类型数据。实参是数组名,形参也应定义为数组形式,形参数组的长度可以省略,但[]不能省,否则就不是数组形式了。

【例5.12】用冒泡法将10个整数排序。2019年3月225.3.2一维数组名作函数参数数组名表示数组在内存中的起始voidsort(intb[],intn);voidprintarr(intb[]);main(){inta[10]={11,22,63,97,58,80,45,32,73,36};printf("Beforesort:\n");

printarr(a);

sort(a,10);

printf("Aftersort:\n");

printarr(a);}voidprintarr(intb[10]){inti;for(i=0;i<10;i++)printf("%5d",b[i]);printf("\n");}voidsort(intb[],intn){inti,j,t;for(i=1;i<n;i++)for(j=0;j<n-i;j++)if(b[j]>b[j+1]){t=b[j];b[j]=b[j+1];b[j+1]=t;}}2019年3月23voidsort(intb[],intn);

a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]

b[0]b[1]b[2]b[3]b[4]b[5]b[6]b[7]b[8]b[9]11226397588045327336(a)排序前a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]b[0]b[1]b[2]b[3]b[4]b[5]b[6]b[7]b[8]b[9]11223236455863738097(b)排序后图7.3调用sort函数2000b形参b实际是一个可以存放地址的变量a:2000实参赋给形参首地址:

2000首地址:

20002019年3月24a[0]a[1]a[2]a[3]a[4]#include"stdio.h"main(){voidscat(charstr1[],charstr2[]);chars1[50],s2[50];inti,k;printf("Inputs1:");gets(s1);printf("Inputs2:");gets(s2);

scat(s1,s2);printf("Outputs1:%s\n",s1);printf("Outputs2:%s\n",s2);}voidscat(charstr1[],charstr2[]){inti=0,k=0;while(str1[i]!='\0')i++;while(str2[k]!='\0'){str1[i]=str2[k];i++;k++;}str1[i]='\0';}scat函数还可简化为:voidscat(charstr1[],charstr2[]){inti=0,k=0;while(str1[i])i++;while(str1[i++]=str2[k++]);}【例5.13】编程序,实现字符串连接。2019年3月25voidscat(charstr1[],charst5.4函数的嵌套调用和递归调用main函数{

……

调用函数A;

……}函数A{……

调用函数B;

……}函数B{

……

……

……}5.4.1函数的嵌套调用2019年3月265.4函数的嵌套调用和递归调用main函数函数A函数B【例5.15】函数的嵌套调用main(){intn=3;printf("%d\n",sub1(n));}sub1(intn){inti,a=0;for(i=n;i>0;i--)a+=sub2(i);returna;}sub2(intn){returnn+1;}程序输出结果:92019年3月27【例5.15】函数的嵌套调用main()sub1(int5.4.2函数的递归调用1.递归的基本概念递归调用:一个函数直接或间接地调用了它本身,就称为函数的递归调用。递归函数:在函数体内调用该函数本身。intsub(intx){inty,z;……if(……)z=sub(y);else{……}return;}例如:直接调用sub函数本身2019年3月285.4.2函数的递归调用1.递归的基本概念递归调用:一个函2.递归函数的执行过程【例5.16】编一递归函数求n!。思路:以求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)2019年3月292.递归函数的执行过程【例5.16】编一递归函数求n!。思路程序如下:floatfact(intn){floatf=0;if(n<0)printf("n<0,error!");elseif(n==0||n==1)f=1;elsef=fact(n-1)*n;return(f);}main(){intn;floaty;printf("\nInputn:");scanf("%d",&n);y=fact(n);printf("%d!=%-10.0f\n",n,y);}运行情况如下:Inputaintegernumber:44!=242019年3月30程序如下:floatfact(intn)main()递归调用过程

回推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}}}}}

递推

2019年3月31递归调用过程3.编制递归函数的方法数值型问题递归函数的编程方法对于数值型问题,首先要找出解题的数学公式,这个公式必须是递归定义的,且所处理的对象要有规律地递增或递减,然后确定递归结束条件。【例5.17】编一递归函数求xn

。思路:首先把xn转化成递归定义的公式xn=1(n=0)x×xn-1

(n>0)再找出递归结束条件:当n=0时,xn=1。2019年3月323.编制递归函数的方法数值型问题递归函数的编程方法xn=1程序如下: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,1010242019年3月33程序如下:longxn(intx,intn)程序运行情5.5局部变量和全局变量及其作用域5.5.1变量的作用域5.5.2局部变量及其作用域变量的作用域:变量在程序中可以被使用的范围。根据变量的作用域可以将变量分为局部变量和全局变量。局部变量(内部变量):在函数内或复合语句内定义的变量以及形参。作用域:函数内或复合语句内。【例5.19】分析下面程序的运行结果及变量的作用域。问题:一个变量在程序的哪个函数中都能使用吗?2019年3月345.5局部变量和全局变量及其作用域5.5.1变量的作用域voidsub(inta,intb){intc;a=a+b;b=b+a;c=b-a;printf("sub:\ta=%db=%dc=%d\n",a,b,c);}局部变量main(){inta=1,b=1,c=1; printf("main:\ta=%db=%dc=%d\n",a,b,c);sub(a,b);printf("main:\ta=%db=%dc=%d\n",a,b,c);

{inta=2,b=2;printf("comp:\ta=%db=%dc=%d\n",a,b,c);}printf("main:\ta=%db=%dc=%d\n",a,b,c);}局部变量局部变量“分程序”或“程序块”程序输出结果:main: a=1b=1c=1sub: a=2b=3c=1main:a=1b=1c=1comp:a=2b=2c=1main: a=1b=1c=12019年3月35voidsub(inta,intb)局部5.5.3全局变量及其作用域全局变量(外部变量):在函数外部定义的变量。作用域:从定义变量的位置开始到本源文件结束。如在其作用域内的函数或分程序中定义了同名局部变量,则在局部变量的作用域内,同名全局变量暂时不起作用。【例5.20】全局变量和局部变量的作用域。2019年3月365.5.3全局变量及其作用域全局变量(外部变量):在函数外inta=5; voidf(intx,inty) {intb,c; b=a+x;c=a-y;printf("%d\t%d\t%d\n",a,b,c);}局部变量main(){intb=6,c=7; f(b,c);printf("%d\t%d\t%d\n",a,b,c);

{inta=9,b=8; printf("%d\t%d\t%d\n",a,b,c);

{

c=10; printf("%d\t%d\t%d\n",a,b,c);

}printf("%d\t%d\t%d\n",a,b,c);

}printf("%d\t%d\t%d\n",a,b,c);}局部变量局部变量程序输出结果:511-2567987981098105610全局变量2019年3月37inta=5; 局部变量main()局部变量局部5.6变量的存储类别及变量的生存期5.6.1变量的生存期与变量的存储分类变量的生存期:变量在内存中占据存储空间的时间。思考:1.

何时为变量分配内存单元?

2.

将变量分配在内存的什么区域?

3.

变量占据内存的时间(生存期)?程序代码区静态存储区动态存储区存储分配动态存储变量静态存储变量2019年3月385.6变量的存储类别及变量的生存期5.6.1变量的生存期5.6.2变量的存储类别变量的属性数据类型:决定为变量分配内存单元的长度,数据的存放形式,数的范围。存储类别:决定了变量的生存期,给它分配在哪个存储区。2019年3月395.6.2变量的存储类别变量的属性数据类型:存储类别:20变量定义语句的一般形式存储类别数据类型变量名1,…,变量名n;auto(自动的)

register(寄存器的)static(静态的)

extern(外部的)1.自动变量(auto类别)局部变量可以定义为自动变量。main()

{intx,y;…}main()

{autointx,y;…}自动变量等价可省2019年3月40变量定义语句的一般形式存储类别数据类型变量名1,⑴内存分配调用函数或执行分程序时在动态存储区为其分配存储单元,函数或分程序执行结束,所占内存空间即刻释放。⑵变量的初值定义变量时若没赋初值,变量的初值不确定;如果赋初值则每次函数被调用时执行一次赋值操作。⑶生存期

在函数或分程序执行期间。⑷作用域自动变量所在的函数内或分程序内。自动变量2019年3月41⑴内存分配自动变量2019年3月412.静态变量(static类别)除形参外,局部变量和全局变量都可以定义为静态变量。局部静态变量(或称内部静态变量)全局静态变量(或称外部静态变量)静态变量静态变量staticinta;main(){floatx,y;…}f(){staticintb=1;……}全局静态变量局部静态变量自动变量不能省2019年3月422.静态变量(static类别)除形参外,局部变量和全局变量⑴内存分配编译时,将其分配在内存的静态存储区中,程序运行结束释放该单元。⑵静态变量的初值若定义时未赋初值,在编译时,系统自动赋初值为0;若定义时赋初值,则仅在编译时赋初值一次,程序运行后不再给变量赋初值。⑶生存期整个程序的执行期间。⑷作用域局部静态变量的作用域是它所在的函数或分程序。全局静态变量的作用域是从定义处开始到本源文件结束。静态变量2019年3月43⑴内存分配静态变量2019年3月43intc;staticinta;main(){floatx,y;…}chars;f(){staticintb=1;……}3.外部变量(extern类别)在函数外定义的变量若没有用static说明,则是外部变量。外部变量只能隐式定义为extern类别,不能显式定义。全局静态变量自动变量局部静态变量外部变量2019年3月44intc;3.外部变量(extern类别)在函数外定义的变⑴内存分配编译时,将其分配在静态存储区,程序运行结束释放该单元。⑵变量的初值若定义变量时未赋初值,在编译时,系统自动赋初值为0。⑶生存期整个程序的执行期间。⑷作用域从定义处开始到本源文件结束。外部变量问题:全局静态变量的作用域可以扩展到本程序的其它文件吗?此外,还可以用extern进行声明,以使其作用域扩大到该程序的其它文件中。2019年3月45⑴内存分配外部变量问题:全局静态变量的作用域可以扩展到本程外部变量声明的一般格式

extern

数据类型变量名1,…,变量名n;或

extern

变量名1,…,变量名n;注意:①外部变量声明用关键字extern,而外部变量的定义不能用extern,只能隐式定义。②定义外部变量时,系统要给变量分配存储空间,而对外部变量声明时,系统不分配存储空间,只是让编译系统知道该变量是一个已经定义过的外部变量,与函数声明的作用类似。2019年3月46外部变量声明的一般格式externintp=1,q=5;floatf1(inta){externcharc1,c2;……}charc1,c2;charf2(intx,inty){……}main(){……}外部变量声明定义外部变量定义外部变量思考:在f1函数中声明c1、c2的作用是什么?如何修改程序使所有函数都可以使用外部变量而又不需要声明?【例5.24】在一个文件内声明外部变量。2019年3月47intp=1,q=5;外部变量声明定义外部变量定义外部变【例5.25】在多文件的程序中声明外部变量。file1.c文件中程序如下:inti;main(){voidf1(),f2(),f3();i=1;f1();printf("\tmain:i=%d",i);f2();printf("\tmain:i=%d",i);f3();printf("\tmain:i=%d\n",i);}voidf1(){i++;printf("\nf1:i=%d",i);}file2.c文件中程序如下:externinti;

voidf2(){inti=3;printf("\nf2:i=%d",i);}voidf3(){i=3;printf("\nf3:i=%d",i);}程序输出结果:f1:i=2main:i=2f2:i=3main:i=2f3:i=3main:i=3声明外部变量定义外部变量2019年3月48【例5.25】在多文件的程序中声明外部变量。file1.c文4.寄存器变量(register类别)只有函数内定义的变量或形参可以定义为寄存器变量。寄存器变量的值保存在CPU的寄存器中。受寄存器长度的限制,寄存器变量只能是char、int和指针类型的变量。【例5.26】寄存器变量的使用。main(){longintsum=0;

registerinti;for(i=1;i<=1000;i++)sum+=i;printf("sum=%ld\n",sum);}程序输出结果:sum=5005002019年3月494.寄存器变量(register类别)只有函数内定义的变量或5.6.3归纳变量的分类1.按照变量的作用域对变量分类 ⑴局部变量 ⑵全局变量2.按照变量的生存期对变量分类 ⑴静态存储变量 包括:局部静态变量和

全局静态变量 ⑵动态存储变量 包括:自动变量2019年3月505.6.3归纳变量的分类1.按照变量的作用域对变量分类205.7函数的存储分类

外部函数:extern

intfan(chara,charb){……}静态函数:static

intfunc(){……}外部函数和静态函数区别:外部函数允许本程序其他文件中的函数调用(与外部变量类似)。静态函数禁止本程序其他文件中的函数调用(与外部静态变量类似)。

extern可以省略2019年3月515.7函数的存储分类外部函数:静态函数:外部函数和静态函第5章函数2019年3月52第5章函数2019年3月1主要内容

5.1概述5.2函数的定义与调用5.3数组作函数参数5.4函数的嵌套调用和递归调用5.5局部变量和全局变量及其作用域5.6变量的存储类别及变量的生存期5.7函数的存储分类2019年3月53主要内容5.1概述2019年3月25.1概述①程序结构清晰,可读性好。②减少重复编码的工作量。③可多人共同编制一个大程序,缩短程序设计周期,提高程序设计和调试的效率。使用函数的好处……C程序源程序文件n函数1函数m……源程序文件1函数1函数n2019年3月545.1概述①程序结构清晰,可读性好。使用函数的……C程序【例5.1】求一个整数的立方。intcube(intx)

/*函数定义*/{return(x*x*x);}main(){intf,a;printf("\nEnteranintegernumber:");scanf("%d",&a);f=cube(a);

printf("%d*%d*%d=%d\n",a,a,a,f);}程序运行情况如下:Enteranintegernumber:22*2*2=8函数调用程序的执行总是从main函数开始2019年3月55【例5.1】求一个整数的立方。intcube(intx⑴一个C源程序可以由一个或多个源程序文件组成。C编译系统在对C源程序进行编译时是以文件为单位进行的。⑵一个C源程序文件可以由一个或多个函数组成。所有函数都是独立的。主函数可以调用其它函数,其它函数可以相互调用。⑶在一个C程序中,有且仅有一个主函数main。C程序的执行总是从main函数开始,调用其它函数后最终回到main函数,在main函数中结束整个程序的运行。说明2019年3月56⑴一个C源程序可以由一个或多个源程序文件组成。C编译系统在⑷函数的种类从函数定义形式分:①有参函数:在主调(用)函数和被调(用)函数之间通过参数进行数据传递,如:

intcube(intx){…}

②无参函数:如:getchar()在调用无参函数时,主调函数不需要将数据传递给无参函数。从使用的角度看:①标准函数(库函数)库函数是由系统提供的。如:getchar()、sin(x)等。在程序中可以直接调用它们。附录3列出了C的部分库函数。②用户自定义函数。如:例5.1中的cube函数。2019年3月57⑷函数的种类从函数定义形式分:从使用的角度看:2019年3【例5.2】无参函数的定义与调用。voidwelcome(){printf("*********************************\n");printf("WelcometoChina\n");printf("*********************************\n");}main(){welcome();}程序的输出结果如下:*********************************

WelcometoChina*********************************2019年3月58【例5.2】无参函数的定义与调用。voidwelcome5.2.1函数的定义函数定义的一般形式函数类型函数名(类型名形式参数1,…

){说明语句

执行语句}例如:求两个数的最大值。

int

max(intx,inty){intz;z=x>y?x:y;return(z);}类型省略时默认为int类型没有形式参数为无参函数

2019年3月595.2.1函数的定义函数定义的一般形式函数类型函数名(类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;{z=x>y?x:y;return(z);}花括号中也可以为空,这种函数叫空函数。不能在函数体内定义其他函数,即函数不能嵌套定义。形参也可以这样定义如下定义都是错误的

√2019年3月60intmax(x,y)intmax(x,y)或花括号中也函数名(实参表列)在C语言中,把函数调用也作为一个表达式。因此凡是表达式可以出现的地方都可以出现函数调用。例如:①welcome();

②if(iabs(a)>max)max=iabs(a);

③m=max(c,max(a,b));5.2.2函数的调用函数调用的一般形式:2019年3月61函数名(实参表列)在C语言中,把函数调用也作为一个表达式。因intsum100(){inti,t=0;for(i=1;i<=100;i++)t+=i;return(t);}main(){ints;s=sum100();printf("%d\n",s);}程序输出结果:5050intsum(intx){inti,t=0;for(i=1;i<=x;i++)t+=i;return(t);}main(){ints;s=sum(100);printf("%d\n",s);}【例5.3】求1~100的累加和。思考:两个程序有何不同程序输出结果:5050?2019年3月62intsum100()程序输出结果:intsum(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);}5.2.3函数参数与函数的返回值1.函数的形式参数与实际参数程序输出结果:x=20,y=10a=10,b=20形式参数(形参)实际参数(实参)【例5.4】编一程序,将主函数中的两个变量的值传递给swap函数中的两个形参,交换两个形参的值。单向值传递2019年3月63voidswap(intx,inty)5.2.3有关形参和实参的说明:

①当函数被调用时才给形参分配内存单元。调用结束,所占内存被释放。②实参可以是常量、变量或表达式,但要求它们有确定的值。③实参与形参类型要一致,字符型与整型可以兼容。④实参与形参的个数必须相等。在函数调用时,实参的值赋给与之相对应的形参。“单向值传递”。注意:在TC中,实参的求值顺序是从右到左。2019年3月64有关形参和实参的说明:①当函数被调用时才给形参分配内存单【例5.5】函数调用中实参的求值顺序。voidfun(inta,intb){printf("a=%d,b=%d\n",a,b);}main(){intm=5;fun(3+m,m++);}程序输出结果:a=9,b=52019年3月65【例5.5】函数调用中实参的求值顺序。voidfun(i2.函数的类型与函数的返回值说明:①函数的类型决定了函数返回值的类型。若省略函数的类型,系统默认其为int型。②无返回值的函数应将其类型定义为void(空)类型。⑴函数的类型【例5.6】输出两个数中的大数。max(intx,inty){intz;z=x>y?x:y;return(z);/*返回z的值*/}main(){inta,b,c;scanf("%d,%d",&a,&b);c=max(a,b);printf("maxis%d\n",c);}2019年3月662.函数的类型与函数的返回值说明:⑴函数的类型【例5.6】函数的返回值是通过return语句带回到主调函数的功能:终止函数的运行,返回主调函数,若有返回值,将返回值带回主调函数。说明:①若函数没有返回值,return语句可以省略。②return语句中的表达式类型一般应和函数的类型一致,如果不一致,系统自动将表达式类型转换为函数类型。⑵函数的返回值return语句格式:return(表达式);

或return表达式;或return;2019年3月67函数的返回值是通过return语句带回到主调函数的功能:终止【例5.8】计算并输出圆的面积。s(intr){return3.14*r*r;}main(){intr,area;scanf("%d",&r);printf("%d\n",s(r));}自动转换为int型思考:若要得到单精度实型的圆面积,程序应如何修改程序运行情况如下:212?2019年3月68【例5.8】计算并输出圆的面积。s(intr)自动转换为i

5.2.4对被调函数的声明和函数原型变量要先定义后使用,函数也如此。即被调函数的定义要出现在主调函数的定义之前。如swap函数:允许整型函数(且参数也是整型)的定义出现在主调函数之后。如max函数:如果非整型函数在主调函数之后定义,则应在主调函数中或主调函数之前对被调函数进行声明。voidswap(intx,inty){…}main(){…swap(a,b);}main(){…c=max(a,b);}max(intx,inty){…}2019年3月695.2.4对被调函数的声明和函数原型变量要先定义后使用对被调函数进行声明的一般形式

函数类型函数名(参数类型1

参数名1,…);或函数类型函数名(参数类型1,参数类型2,…);思考:以下哪种情况需要在主调函数中对被调函数声明被调函数定义在前,主调函数定义在后。主调函数定义在前,被调函数定义在后。第二种形式省略了参数名,此种形式也称为函数的原型。?2019年3月70对被调函数进行声明的一般形式函数类型函数名(参main(){voidcalc(floatx,floaty,charopr);

floata,b;charopr;printf("\nInputexpression:");scanf("%f%c%f",&a,&opr,&b);calc(a,b,opr);}voidcalc(floatx,floaty,charopr){switch(opr){case'+':printf("%5.2f%c%5.2f=%6.2f\n",x,opr,y,x+y);return;case'-':printf("%5.2f%c%5.2f=%6.2f\n",x,opr,y,x-y);return;case'*':printf("%5.2f%c%5.2f=%6.2f\n",x,opr,y,x*y);return;case'/':printf("%5.2f%c%5.2f=%6.2f\n",x,opr,y,x/y);return;default:printf("Operatorerr!\n");}}对被调函数的声明【例5.9】计算并输出两个数的和、差、积、商。2019年3月71main()对被调函数的声明【例5.9】计算并输出两个数的5.3数组作函数参数5.3.1一维数组元素作函数参数main(){inta[5],i,m;for(i=0;i<5;i++)scanf("%d",&a[i]);m=a[0];for(i=1;i<5;i++)m=min(m,a[i]);printf("%d\n",m);}【例5.11】求5个数中的最小值。intmin(intx,inty){return(x<y?x:y);}用打擂台方法求最小值。m相当于擂主2019年3月725.3数组作函数参数5.3.1一维数组元素作函数参数ma5.3.2一维数组名作函数参数数组名表示数组在内存中的起始地址。例如:数组a在内存中从2000地址开始存放,则a的值为2000。2000是地址值,是指针类型的数据(后面将介绍指针类型),不能把它看成是整型或其他类型数据。实参是数组名,形参也应定义为数组形式,形参数组的长度可以省略,但[]不能省,否则就不是数组形式了。

【例5.12】用冒泡法将10个整数排序。2019年3月735.3.2一维数组名作函数参数数组名表示数组在内存中的起始voidsort(intb[],intn);voidprintarr(intb[]);main(){inta[10]={11,22,63,97,58,80,45,32,73,36};printf("Beforesort:\n");

printarr(a);

sort(a,10);

printf("Aftersort:\n");

printarr(a);}voidprintarr(intb[10]){inti;for(i=0;i<10;i++)printf("%5d",b[i]);printf("\n");}voidsort(intb[],intn){inti,j,t;for(i=1;i<n;i++)for(j=0;j<n-i;j++)if(b[j]>b[j+1]){t=b[j];b[j]=b[j+1];b[j+1]=t;}}2019年3月74voidsort(intb[],intn);

a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]

b[0]b[1]b[2]b[3]b[4]b[5]b[6]b[7]b[8]b[9]11226397588045327336(a)排序前a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]b[0]b[1]b[2]b[3]b[4]b[5]b[6]b[7]b[8]b[9]11223236455863738097(b)排序后图7.3调用sort函数2000b形参b实际是一个可以存放地址的变量a:2000实参赋给形参首地址:

2000首地址:

20002019年3月75a[0]a[1]a[2]a[3]a[4]#include"stdio.h"main(){voidscat(charstr1[],charstr2[]);chars1[50],s2[50];inti,k;printf("Inputs1:");gets(s1);printf("Inputs2:");gets(s2);

scat(s1,s2);printf("Outputs1:%s\n",s1);printf("Outputs2:%s\n",s2);}voidscat(charstr1[],charstr2[]){inti=0,k=0;while(str1[i]!='\0')i++;while(str2[k]!='\0'){str1[i]=str2[k];i++;k++;}str1[i]='\0';}scat函数还可简化为:voidscat(charstr1[],charstr2[]){inti=0,k=0;while(str1[i])i++;while(str1[i++]=str2[k++]);}【例5.13】编程序,实现字符串连接。2019年3月76voidscat(charstr1[],charst5.4函数的嵌套调用和递归调用main函数{

……

调用函数A;

……}函数A{……

调用函数B;

……}函数B{

……

……

……}5.4.1函数的嵌套调用2019年3月775.4函数的嵌套调用和递归调用main函数函数A函数B【例5.15】函数的嵌套调用main(){intn=3;printf("%d\n",sub1(n));}sub1(intn){inti,a=0;for(i=n;i>0;i--)a+=sub2(i);returna;}sub2(intn){returnn+1;}程序输出结果:92019年3月78【例5.15】函数的嵌套调用main()sub1(int5.4.2函数的递归调用1.递归的基本概念递归调用:一个函数直接或间接地调用了它本身,就称为函数的递归调用。递归函数:在函数体内调用该函数本身。intsub(intx){inty,z;……if(……)z=sub(y);else{……}return;}例如:直接调用sub函数本身2019年3月795.4.2函数的递归调用1.递归的基本概念递归调用:一个函2.递归函数的执行过程【例5.16】编一递归函数求n!。思路:以求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)2019年3月802.递归函数的执行过程【例5.16】编一递归函数求n!。思路程序如下:floatfact(intn){floatf=0;if(n<0)printf("n<0,error!");elseif(n==0||n==1)f=1;elsef=fact(n-1)*n;return(f);}main(){intn;floaty;printf("\nInputn:");scanf("%d",&n);y=fact(n);printf("%d!=%-10.0f\n",n,y);}运行情况如下:Inputaintegernumber:44!=242019年3月81程序如下:floatfact(intn)main()递归调用过程

回推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}}}}}

递推

2019年3月82递归调用过程3.编制递归函数的方法数值型问题递归函数的编程方法对于数值型问题,首先要找出解题的数学公式,这个公式必须是递归定义的,且所处理的对象要有规律地递增或递减,然后确定递归结束条件。【例5.17】编一递归函数求xn

。思路:首先把xn转化成递归定义的公式xn=1(n=0)x×xn-1

(n>0)再找出递归结束条件:当n=0时,xn=1。2019年3月833.编制递归函数的方法数值型问题递归函数的编程方法xn=1程序如下: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,1010242019年3月84程序如下:longxn(intx,intn)程序运行情5.5局部变量和全局变量及其作用域5.5.1变量的作用域5.5.2局部变量及其作用域变量的作用域:变量在程序中可以被使用的范围。根据变量的作用域可以将变量分为局部变量和全局变量。局部变量(内部变量):在函数内或复合语句内定义的变量以及形参。作用域:函数内或复合语句内。【例5.19】分析下面程序的运行结果及变量的作用域。问题:一个变量在程序的哪个函数中都能使用吗?2019年3月855.5局部变量和全局变量及其作用域5.5.1变量的作用域voidsub(inta,intb){intc;a=a+b;b=b+a;c=b-a;printf("sub:\ta=%db=%dc=%d\n",a,b,c);}局部变量main(){inta=1,b=1,c=1; printf("main:\ta=%db=%dc=%d\n",a,b,c);sub(a,b);printf("main:\ta=%db=%dc=%d\n",a,b,c);

{inta=2,b=2;printf("comp:\ta=%db=%dc=%d\n",a,b,c);}printf("main:\ta=%db=%dc=%d\n",a,b,c);}局部变量局部变量“分程序”或“程序块”程序输出结果:main: a=1b=1c=1sub: a=2b=3c=1main:a=1b=1c=1comp:a=2b=2c=1main: a=1b=1c=12019年3月86voidsub(inta,intb)局部5.5.3全局变量及其作用域全局变量(外部变量):在函数外部

温馨提示

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

评论

0/150

提交评论