C语言程序设计课件-第4章 函数_第1页
C语言程序设计课件-第4章 函数_第2页
C语言程序设计课件-第4章 函数_第3页
C语言程序设计课件-第4章 函数_第4页
C语言程序设计课件-第4章 函数_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

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

文档简介

第4章函数

按结构化程序设计的要求,通常可将程序按功能分成若干模块,每个模块又可分成更小的模块,逐层细化至每个模块只完成特定的功能。按此原则编写的程序层次清晰、可读性强、易于修改和维护,亦便于多个成员合作编写程序。

C语言中,模块由函数实现。函数是完成特定功能的程序段,是C程序的基本单位。一个C程序由一个或多个函数组成,这些函数可以放在一个或多个源程序文件中。

4.1.1函数的基本概念

C程序中有一个函数是必须存在的,这就是main函数(又称为主函数)。main函数是唯一的。main函数是C程序执行的入口,即程序开始执行时,系统首先调用main函数执行。

C程序中所有函数的定义是平行的,函数之间不存在嵌套或从属的关系,但是函数之间可以相互调用。除main函数不能被其他函数调用外,其他函数都是一个可以反复使用的程序段。函数是通过被调用而执行的。【例4.1】编写程序计算两个整数绝对值阶乘之差。

#include"math.h"

#include"stdio.

intfac(intn)/*计算一个整数绝对值的阶乘*/

{inti,f=1;

n=abs(n);

for(i=1;i<=n;i++)

f=f*i;

return(f);

}main(){intx,y,c1,c2;printf("pleaseenterx,y:");scanf("%d%d",&x,&y);c1=fac(x);/*调用fac,求x绝对 值的阶乘*/c2=fac(y);/*调用fac,求y绝对值 的阶乘*/printf("theoutcomeis%d\n",c1-c2);/*输出结果*/}输入-7、2时的运行结果为:pleaseenterx,y:-72↙theoutcomeis5038

函数是有区别的:

系统函数(库函数):可以直接使用,由C系统提供,如 scanf、printf和abs函数。

用户自定义函数:还有一种是用户必须定义后才能使用的 函数,例如例6.1中的fac函数。4.1.2函数的定义

●编写C程序的主要工作就是编写用户自定义函数,即 所谓的函数定义。

●函数定义的一般形式:

类型标识符函数名(形式参数表列)

{

声明部分

执行部分

}

【例4.2】求两个整数的之和。

#include“stdio.h”

voidstart_information()

{printf(“Theprogrambegin!\n”);

}

intsum(intx1,intx2)/*定义函数 的返回值类型,函数名,形参*/

{ints;

s=x1+x2;/*计算x1和x2之和*/

return(s);/*返回运算结果*/

}

voidend_information()

{printf("Theprogramend!\n");

}

main(){intx,y,z,s;start_information();printf("enterxy:");scanf("%d%d",&x,&y);s=sum(x,y);printf("thesumis%d\n",s);end_information();}输入23、4时,程序运行结果为:Theprogrambegin!enterxy:234↙thesumis27Theprogramend!编写函数注意:

①函数名要符合标识符的命名规则,例如,

start_information

end_information。

②函数定义时的参数称为形式参数,简称形参。

●形式参数列表说明的是函数间要传递的数据。

●函数调用时主调函数把实际参数传递给形式参数,然 后被调用函数利用实际参数进行运算。

③若有多个形参,形参之间用逗号分隔。

例如,“intsum(intx1,intx2)”。

④如果在形式参数列表中只列出参数名,则需要在其后说明每个参数的类型,函数定的形式变为:

类型标识符函数名(形式参数表列)

形式参数类型说明;

{声明部分

执行部分

}

intsum(x1,x2)/*定义返回值类型,函数名,形参*/

intx1,x2;

{ints;

s=x1+x2;/*计算x1和x2之和,放到s中*/

return(s);/*返回运算结果*/

}⑤如果函数不需要数据传递,形式参数表为空,但“()”不能省略。

例如start_information()

end_information()。

⑥花括弧内的内容称为“函数体”。

声明部分对函数内使用变量定义和声明,以及对被调用函数的声明。

执行部分是实现函数功能的语句序列。4.2函数参数与返回值

4.2.1函数的参数

●函数的参数分为形参和实参两种。

●形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。

●实参出现在主调中,进入被调函数后,实参变量也不能使用。●形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参(单向值传递),从而实现主调函数向被调函数的数据传送。形参和实参特点:

(1)形参变量只有在被调用时才分配内存单元,在调用结束时即刻释放所分配的内存单元。因此形参只有在函数内部有效,函数调用结束返回主调函数后,就不能再使用该形参变量。

(2)实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。

(3)实参和形参在数量上、类型上、顺序上应严格一致,否则会发生“类型不匹配”的错误。

(4)函数调用中发生的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变对实参中的值不会有影响。【例4.3】函数调用举例。

#include<stdio.h>

main()

{

voids(intn);

intn;

printf(“inputnumber\n”);

scanf(“%d”,&n);

s(n);

printf(“n=%d\n”,n);

}voids(intn){inti;for(i=n-1;i>=1;i--)n=n+i;printf(“n=%d\n”,n);}程序分析:

本程序中定义了一个函数s,该函数的功能是求∑i(i从n-1变到1)的值。在主函数中输入n的值(假设n为100),并作为实参,在调用时传送给s函数的形参变量n(注意,本程序的形参变量和实参变量的标识符都为n,但这是两个不同的量,各自有不同的作用域)。在主函数中用printf语句输出一次n的值,这个n的值是实参n的值。在函数s中也用printf语句输出了一次n值,这个n值是形参最后取得的n值5050。从运行情况看,输入n值为100,即形参n的值变为5050。返回主函数之后,输出实参n的值仍为100。可见实参的值不随形参的变换而变化。

4.2.2函数的返回值

函数的返回值是指函数被调用后,执行函数体的程序段所取得并返回给主调函数的值。

(1)函数的值只能通过return语句返回主调函数。

return语句格式为:return(<表达式>);

(2)return语句功能:

①将表达式的计算结果返回给调用函数。

②结束函数的执行,返回到主调函数中继续执行。【例4.4】编程序求两个浮点数的积。

floatproduct(floatx,floaty)/*`计算两个浮点数的积*/

{floats;

s=x*y;

return(s);

}

main()

{floata,b,p;

printf("\npleaseenter(a,b):");/*输出信息提示*/

scanf("%f,%f",&a,&b);

p=product(a,b);/*调用函数product*/

printf("theproductofa,bis:%f\n",p);

}说明:

①返回值的类型应为定义函数时的函数的类型。若函数类型与return语句中表达式值的类型不一致,则以函数类型为准进行类型转换。例如,如果product函数为:

doubleproduct(floatx,floaty)/*计算两个浮点数的积*/

{floats;

s=x*y;

return(s);

}

②没有返回值的函数,用void定义其函数类型。否则,函数即使不用return语句返回值,函数仍将返回一个不确定的值。

③如果return语句中没有返回值,语句格式为:return;

④return语句可以出现多次,但是每次函数调用只能有一条 return语句被执行。return语句返回值是float类型,而函数类型为double,则将返回值转换成double类型返回。例如下面的example函数有三个return语句,只要其中之一执行,函数就会结束。最后一个return语句中没有返回值,其功能只是返回调用函数。

doubleexample(floatx,floaty)

{floats;

if(x>0&&y>0){s=x/y;return(s);}

if(y==0)return(0);

return;

}

4.3函数调用

4.3.1函数的声明

在C程序中,函数可以被调用需要两个前提:

①函数已存在。系统函数,或用户已定义完成的函数。

②对于库函数,在调用函数所在文件用include命令包含相应 的头文件即可;

③对于用户自定义的函数,除三种情况外都需要在调用函数前 对其进行声明,或者用include命令包含被调用函数的所 在文件。

●函数定义是指编写不存在的函数,函数定义只能一次。

●函数声明是对存在的准备调用的函数进行声明,让编译系统可以在编译阶段对函数的调用进行合法性检查,判断形参与实参的类型及个数是否一致,函数声明可以多次。

函数声明格式:类型标识符函数名(形式参数表列);

main()

{floata,b,p;

floatproduct(floatx,floaty);/*函数声明,以便本函数调用*/

printf("\npleaseenter(a,b):");

scanf("%f,%f",&a,&b);

p=product(a,b);/*调用函数product*/

printf("\ntheproductofa,bis:%f",p);

}

floatproduct(floatx,floaty)/*计算两个浮点数的积*/

{floats;

s=x*y;

return(s);

}下列三种情况下,调用函数前可以不对被调用函数进行声明:

①被调函数的返回值类型是整型或字符型。

②在函数的外部已对该函数声明,且声明在主调函数的前面。

floatproduct(floatx,floaty);/*函数product的声明语句*/

main()

{floata,b,p;

printf("\npleaseenter(a,b):");

scanf("%f,%f",&a,&b);

p=product(a,b);/*调用函数product*/

printf("\ntheproductofa,bis:%f",p);

}

floatproduct(floatx,floaty)/*计算两个浮点数的积*/

{floats;

s=x*y;

return(s);}

③被调用函数的定义和调用函数在同一个文件内,且出现在调用函数之前。

floatproduct(floatx,floaty)/*计算两个浮点数的积*/

{floats;

s=x*y;

return(s);

}

main()

{floata,b,p;

printf("\npleaseenter(a,b):");/*输出信息提示*/

scanf("%f,%f",&a,&b);

p=product(a,b);/*调用函数product*/

printf("theproductofa,bis:%f\n",p);

}

4.3.2函数的调用

函数的调用就是调用函数通过数据传递使用被调用函数的功能。

函数调用的一般形式是:

函数名(实际参数表列)

说明:

①调用函数时的参数称为实际参数,简称实参。实参可以是变 量、常量或表达式,是有确定值的参数。

②函数的形参与实参要求个数相等,并且对应的形参和实参的 类型相同。若被调函数是无参函数,则实参表列为空。

③数据传递是通过形参接收实参的数值完成的。函数调用时, 形参被分配内存单元,并接收对应实参传来的值。#include“stdio.h”

voidstart_information()

{printf(“Theprogrambegin!\n”);

}

voidend_information()

{printf(“Theprogramend!\n”);

}

floatsort(floatx1,floatx2,floatx3)

{floatt;

printf(“x1=%6.2fx2=%6.2fx3=%6.2f\n”,x1,x2,x3);

if(x1>x2){t=x1;x1=x2;x2=t;}

if(x1>x3){t=x1;x1=x3;x3=t;}

if(x2>x3){t=x2;x2=x3;x3=t;}

printf("x1=%6.2fx2=%6.2fx3=%6.2f\n",x1,x2,x3);

return(x3+x2+x1);

}

main(){floata,sum;start_information();printf("pleaseenterdata(a):");scanf("%f",&a);sum=sort(a+1,3.0,a);printf("sumis%6.2f\n", sum);end_information();}【例4.7】将三个实数按由小到大顺序输出。一般函数的三种调用方式:

①具有返回值的函数参加表达式的计算。例如语句 t=max(x,y)+10;

②具有返回值的函数作为其他函数的实参。例如语句 printf(“\nthemaximumis:%f”,max(t,z));

③没有返回值的函数单独成为一个语句,例如语句:

end_information();

【例4.8】函数调用方式。

floatmax(floatx,floaty)/*返回两个数中较大的值*/

{if(x>y)return(x);elsereturn(y);

}

voidend_information()

{printf(“Theprogramend!\n”);

}

main()

{floatx,y,z,t;

printf("pleaseenterxyz:");/*输出信息提示输入三个实数*/

scanf("%f%f%f",&x,&y,&z);

t=max(x,y)+10;

printf("themaximumis:%f\n",max(t,z));

end_information();

}4.3.3函数调用的数据传递方式

●C语言中,只能将实参的值传递给形参,形参值的 变化不影响实际参数。称为单向值传递。

●调用函数时,给形参分配内存单元,将实参的值赋给形式参数。

●函数执行完后,形参占用的空间被释放,实参仍为调用前的值。

【例4.10】注意程序运行结果。voidchange(intx,inty){printf("x=%d,y=%d\n",x,y);

x=100;y=200;printf("x=%d,y=%d\n",x,y);}

main(){inta,b;printf("\npleaseenter data(a,b):");scanf("%d%d",&a,&b);printf("a=%d,b=%d\n",a,b);change(a,b);printf("a=%d,b=%d\n",a,b);}在输入3、4时,程序的运行结果为:pleaseenterdata(a,b):34↙a=3,b=4x=3,y=4x=100,y=200a=3,b=4

例4.10中main函数调用函数change时,系统给形参x、y分配空间,将实参a的值赋给形参x,实参b的值赋给形参y。执行change函数时,x、y重新被赋值。change函数执行完x、y占用的空间被释放。形参x、y的变化影响不到实参a、b,因此main函数内输出为“a=3,b=4”。4.4函数的嵌套调用

4.4.1函数的嵌套调用

C语言中,函数不允许嵌套定义,但可以嵌套调用。【例4.11】求两个整数的最小公倍数。intdivisor(intx,inty)/*求整数x、y的最大公约数*/{

intm;

if(x<y){m=x;x=y;y=m;}while((m=x%y)!=0){x=y;y=m;}return(y);}

intmultiple(intx,inty)/*求整数x、y的最小公倍数*/{intm;m=x*y/divisor(x,y);return(m);}

main(){intx,y,z;

printf("\npleaseenterxy:");scanf("%d%d",&x,&y);z=multiple(x,y);/*调用函数multiple 求x、y的最小公倍数*/printf("theminimumcommonmultiple: %d",z);}

例4.11的程序运行过程如图4.1所示。从main函数开始执行,输入两个整数后调用multiple函数,multiple函数用调用了divisor函数。divisor函数执行完返回multiple函数执行,multiple函数执行完返回main函数执行。main函数执行完,程序执行结束。voidf3()

{printf("functionf3begin.\n");

printf("functionf3end.\n");

}

voidf2()

{printf("functionf2begin.\n");

f3();

printf("functionf2end.\n");

}

voidf1()

{printf("functionf1begin.\n");

f2();

f3();

printf("functionf1end.\n");

}

main(){printf("\nfunctionmainbegin.\n");f1();printf("functionmainend. \n");}

functionmainbegin.functionf1begin.

functionf2begin.

functionf3begin.functionf3end.

functionf2end.

functionf3begin.functionf3end.functionf1end.functionmainend.【例4.12】请分析下列程序的输出结果,体会函数嵌套调用的关系。4.4.2函数的递归调用

●函数可以直接或间接的调用自身,这种调用方式称为函数 的递归调用。

●注意,虽然递归是直接或间接的调用自身,但和调用其他 函数一样每次被调用都需要重新开辟空间,并不共用 同一内存空间。因此调用自身和调用其他函数的调用 过程无区别。【例4.13】直接递归调用。

voidfun()

{printf("functionfunbegin.\n");

fun();

printf("functionfunend.\n");

}

【例4.14】间接递归调用。voidf1(){printf("functionf1begin.\n");f2(),printf("functionf1end.\n");}voidf2(){printf("functionf2begin.\n");f1();printf("functionf2end.\n");}

例4.13和例4.14的递归调用是无休止的自身调用。显然无休止的调用是不合理的,也是不允许的。合理的递归调用应是有限的,是在一定条件能停止的递归调用。【例4.15】求n!的递归程序。

longfac(intx)/*递归函数,求x!*/

{if(x<0)return(-1);/*无法计算阶乘返回-1*/

elseif(x==1||x==0)return(1);/*返回终结条件下的值*/

elsereturn(x*fac(x-1));/*递归调用函数自身*/

}

main()

{intn;

printf("pleaseenterintegern:");

scanf("%d",&n);

printf("n!=%ld\n",fac(n));

}

main()fac(3)fac(2)fac(1)

输入n

调用fac函数求3! 计算3*fac(2)计算2*fac(1)1!=1

输出3!结束返回fact(3)=6

温馨提示

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

评论

0/150

提交评论