任务五 模块化程序设计.doc_第1页
任务五 模块化程序设计.doc_第2页
任务五 模块化程序设计.doc_第3页
任务五 模块化程序设计.doc_第4页
任务五 模块化程序设计.doc_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

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

文档简介

任务五 模块化程序设计任务五 模块化程序设计5.1 教学目标1. 理解C语言模块化程序设计的思想2. 掌握函数的定义和调用5.2 工作任务1. 无返回值函数的调用2. 有返回值函数的调用3. 数组和指针作为函数参数的应用4. 函数的嵌套和递归调用5.3 相关实践知识在使用C语言设计较复杂的程序时,通常先把问题分解成几个部分,再根据每个部分应完成的功能编写出相应的程序段,这些具有独立功能的程序段就称为函数。使用函数,就能将原来较复杂的程序设计分解为相对简单的程序段设计。5.3.1 无返回值函数的调用【案例5-1】编写一个显示欢迎信息的程序,输入姓名,显示欢迎信息。算法分析:编写一个message()函数用于显示欢迎信息。在main()函数中输入姓名,调用message()函数,显示完整的欢迎信息。C语言程序如下:#include #include void message(char *s); /*函数原型声明*/void main()char name10; printf(Please input your name:n); scanf(%s,name); message(name); /*函数调用*/void message(char *s) /*函数定义*/ int n,i; printf(%s Welcome to the C world!n,s);程序说明: void message(char *s); :函数原型声明语句,声明主函数中需要调用后面的message()函数。 程序从main()函数开始执行,输入姓名赋给变量name。message(name)语句调用message()函数,并将name作为参数传递过去。 message()函数执行,输出显示欢迎信息。 message()函数执行完毕返回main()函数。 main()函数执行完毕,程序结束。运行结果如下:Please input your name:SunnySunny Welcome to the C world!5.3.2 有返回值函数的调用【案例5-2】编写程序计算两个整数绝对值阶乘之差。算法分析:编写一个fac()函数计算一个整数x的绝对值阶乘。在main()函数中分两次调用fac()函数,分别求出x和y的绝对值阶乘,再计算两者的差值。C语言程序如下:#include #include #include int fac(int n) int i,f=1; n=abs(n); for(i=1;i=n;i+) /*计算一个整数绝对值的阶乘*/ f=f*i; return(f);void main() int x,y,c1,c2; printf(please input x,y:n); scanf(%d,%d,&x,&y); c1=fac(x); /*调用函数fac,求x绝对值的阶乘*/ c2=fac(y); /*调用函数fac,求y绝对值的阶乘*/ printf(The outcome is %dn,c1-c2); /*输出结果*/运行结果如下:please input x,y:6,5The outcome is 600程序说明: return(f)是将f作为函数的值返回给主调函数 c1=fac(x)是将实际参数x传递给fac(int n)函数的形式参数n【案例5-3】输入长方体的长宽高l,w,h,求体积及三个面x*y,x*z,y*z的面积。C语言程序如下:int s1,s2,s3; /* 定义全局变量b,c */int count( int a,int b,int c) /* 定义局部变量a,b,c */ int v; /* 定义局部变量v */ v=a*b*c; s1=a*b; s2=b*c; s3=a*c; return v;void main() int v,l,w,h; /* 定义局部变量v,l,w,h */ printf(Please input length,width and height:n); scanf(%d,%d,%d,&l,&w,&h); v=count(l,w,h); printf(v=%d s1=%d s2=%d s3=%dn,v,s1,s2,s3);运行结果如下:Please input length,width and height:1,2,3v=6 s1=2 s2=6 s3=3程序说明: 本程序中定义了三个全局变量s1,s2,s3,用来存放三个面积,其作用域为整个程序。 函数count()用来求正方体体积和三个面积,函数的返回值为体积v。由主函数完成长宽高的输入及结果输出。5.3.3 数组和指针作为函数参数的应用【案例5-4】编写一个函数实现两个数交换。算法分析:编写一个swap()函数实现对a,b两个数的交换。在main()函数中调用swap()函数,交换后输出结果。C语言程序如下:#include void swap(int *a,int *b); /*函数声明*/void main() int x,y; x=10; y=20; printf(Before swapping:x=%d y=%dn,x,y); swap(&x,&y); /*函数调用*/ printf(After swapping:x=%d y=%dn,x,y);void swap(int *a,int *b) /*函数定义*/ int t; t=*a; *a=*b; *b=t;运行结果如下:Before swapping:x=10 y=20After swapping:x=20 y=10程序说明: void swap(int *a,int *b)中定义两个指针类型的形参int *a和int *b,分别表示需要交换的两个数; 函数调用使用语句swap(&x,&y),将x的地址传递指针类型的形参a, 将y的地址传递指针类型的形参b。 【案例5-5】编写一个求一维数组最大值的函数。算法分析:编写一个max()函数实现对形参数组求最大值。在main()函数中调用max ()函数,对x数组求最大值,输出结果。C语言程序如下:#include #include int max_value(int a,int n); /*函数声明*/void main() int x10,i,max; randomize(); printf(array:n); for(i=0;i10;i+) xi=random(90)+10; printf(%3d,xi); max=max_value(x,10); /*函数调用*/ printf(nThe max value is %dn,max); getch();int max_value(int a,int n) /*函数定义*/ int i,t; t=a0; for(i=1;it) t=ai; return(t);运行结果如下:array:76 34 55 45 37 93 80 90 51 84The max value is 93程序说明: 定义max函数时,定义两个形参int a和int n,分别表示需求最大值的数组和数组元素的个数; 函数调用使用语句max_value(x,10),将x的首地址传递给形参数组a。 5.3.4 函数的嵌套调用和递归调用【案例5-6】输入一个整数n,求12+22+32+n2的值。算法分析:编写一个function2()函数计算一个整数x的平方,编写一个function1()函数求和。function1()函数中调用function2()求平方,函数main() 函数中调用function1()函数求算式的和。此题属于函数的嵌套调用,执行过程见图5-1:图5-1 函数嵌套执行过程C语言程序如下:#includeint function2(int x) int y; y=x*x; return(y);void function1(int x) int i; long sum; sum=0; for(i=1;i1)算法分析:当n不为0和1时,n!=n*(n-1)!,当n-1不为0和1时,(n-1)!=(n-1)*(n-2)!,因而该题可以用递归调用的方法编程实现。以n=3为例,执行过程见图5-2:图5-2 求3!的递归执行过程C语言程序如下:#include #include #include float fact(int n);void main( ) int i,n; float s; printf(Please input n:n); scanf(%d,&n); s= fact(n); /*调用fact(n)函数求阶乘*/ printf(s=%fn,s);float fact(int n) float f; if(n=0|n=1)f=1; else f=n*fact(n-1); /*递归调用fact(n)函数*/ return(f); 运行结果如下:Please input n:3s=6.000000程序说明: 本程序中采用了函数递归调用的方式,在主函数main()中,提示用户输入n的值。 在函数fact()中,对n求阶乘,当n为1或0时,fact(n)的返回值f=1。否则fact(n)的返回值f =n*fact(n-1)。 当n-1不为0或1时,再次调用fact()函数,直到递减到1,求出最终结果。5.4 相关理论知识5.5.1 C语言的程序结构C语言程序通常由多个函数组成的,每个函数均可完成一定的功能,依一定的规则调用这些函数,就可组成解决某个特定问题的程序。C语言程序的结构如图5-3所示,方框表示用函数定义的模块,线条表示调用关系。C程序的执行总是从main()函数开始,完成对其他函数的调用后再返回到main()函数,最后由main()函数结束整个程序。因此main()函数又称为主函数,它可以调用其他函数,而不允许被其他函数调用,一个C语言程序有且仅有一个主函数main()。图5-3 C语言程序结构图在语言中可从不同的角度对函数分类。1. 从函数定义的角度看,函数可分为库函数和用户自定义函数两种。(1) 库函数由系统提供,用户无需定义, 也不必在程序中作类型说明,只需在程序前包含有该函数原型的头文件即可在程序中直接调用。在前面各章的例题中反复用到的printf()、 scanf()、 getchar()、putchar()等函数都属于库函数。 (2) 用户自定义函数由用户按需要写的函数。对于用户自定义函数,不仅要在程序中定义函数本身,而且在主调函数模块中还必须对该被调函数进行类型说明,然后才能使用。本章我们要学习的就是如何定义和使用用户自定义函数。2. C语言程序的书写结构C语言程序的书写结构如图5-4所示,通常分为三大部分:即文件包含部分(编译预处理)、类型定义说明部分(变量说明、函数说明等)、函数定义部分。文件包含类型定义说明部分函数1定义函数2定义函数n定义图5-4 程序的书写结构5.5.2 无返回值函数的定义和调用1. 无返回值函数的定义无返回值函数用于完成某项特定的处理任务,执行完成后不向调用者返回函数值。无返回值函数定义的一般形式如下:void 函数名(形式参数列表) /*函数说明*/ /*函数体*/ 局部变量声明 执行语句(1) 函数说明函数说明部分包括函数的类型、函数名、形式参数列表。无返回值函数不返回任何值,因此在定义函数类型时,在函数名前用说明符void定义为空类型。函数体形式参数列表根据具体的函数需要确定个数和类型,如果形参列表包含多个形参,则各形参之间用逗号分隔。形参可以为空,但是圆括号不能省。如例5-1中定义函数message () 使用语句:void message(char *s) 说明返回类型为空,有一个字符型的形式参数。 (2) 函数体函数定义的花括号“ ”里的部分是函数体。函数体一般由两部分组成,一部分是局部变量声明,另一部分是执行语句。2. 无返回值函数的调用(1) 函数的声明在调用某个已经定义了的函数时,一般还应对被调用函数进行声明,其作用是告知编译程序本函数将要调用这个函数。函数声明的形式为:void 函数名(形式参数列表);声明的位置可以在主调函数中,也可以在程序的类型定义说明部分,注意分号不能少。如例5-1中void message(char *s);如果被调用函数在主调函数前已经定义过,就可以不用声明了。(2) 函数的调用C语言中,无返回值函数调用的一般形式是作为一条函数语句,不返回值,只是要求函数完成一定的操作:无返回值函数调用的形式为:函数名(实参列表);实参列表必须与定义函数时的形参列表个数相同,类型一致,如果实参列表包含多个实参,则各实参之间用逗号分隔。对于无参函数调用时则无实际参数表,但是圆括号不能省。例5-1中通过语句 message(name);调用message()函数。5.5.3 有返回值函数的定义和调用1. 有返回值函数的定义有返回值函数在被调用执行完后将向调用者返回一个执行结果,称为函数返回值。由用户定义的这种要返回函数值的函数,必须在函数定义和函数声明中明确返回值的类型。有返回值函数定义的一般形式如下:类型标识符 函数名(形式参数列表) /*函数说明*/ /*函数体*/ 局部变量声明 执行语句 (1) 函数说明和无返回值函数相同,函数说明部分包括函数的类型、函数名、形式参数列表。但在函数名前用类型标识符定义本函数的类型。有返回值函数调用后要返回值,因此函数的类型实际上是函数返回值的类型。函数体形式参数列表根据具体函数的需要确定个数和类型,可以为空。(2) 函数体和无返回值函数相同,函数定义的花括号“ ”里的部分是函数体。函数体一般由两部分组成,一部分是局部变量声明,另一部分是执行语句。但是在执行语句中,要通过return语句将函数的值返回给主调函数。return语句的一般形式为: return 表达式;或者为: return (表达式);return语句的功能是计算表达式的值,并返回给主调函数。在函数中允许有多个return语句,但每次调用只能有一个return语句被执行,因此只能返回一个函数值。2. 有返回值函数的调用(1) 函数的声明和无返回值在调用一样,一般还应对被调用函数进行声明,如果被调用函数在主调函数前已经定义过了,就可以不用声明了。函数声明的形式为类型名 函数名(形式参数列表);(2) 函数的调用在C语言中,有返回值函数因为要返回结果,所以在调用的时候是当作相应类型的值在主调函数中使用,调用的一般形式为: 函数表达式 函数出现在一个表达式中,则这个表达式称为函数表达式,最简单的表示式就是:变量=函数名(实参列表);如例5-2中两次调用函数fac 的语句分别为c1=fac(x)和 c2=fac(y)。 函数参数 函数的返回值作为函数再次调用的参数,实际上是函数表达式形式调用的一种。5.5.4 函数的参数传递从主调函数和被调函数之间数据传送的角度来看,函数又可分为无参函数和有参函数两种。1. 无参函数函数定义、函数说明及函数调用中均不带参数。主调函数和被调函数之间不进行参数传送。此类函数通常用来完成一组指定的功能,可以返回或不返回函数值。例如以下Hello()函数就是一个无参函数,当被其它函数调用时,输出Hello world字符串。void Hello()printf (Hello,world !n);2. 有参函数有参函数在函数定义、函数声明中带有参数,为形式参数。在函数调用时也带有参数,为实际参数。进行函数调用时,主调函数将把实参的值传送给形参,供被调函数使用。说明:(1) 定义和声明函数时的参数称为形式参数,调用函数时的参数称为实际参数。函数的形参和实参个数相等,并且相对应的形参和实参类型必须相同。(2) 实参可以是常量、变量或表达式,是有确定值的参数。(3) 函数调用时,形参被分配内存单元,并接受对应实参传递过来的数值。调用结束后立即释放内存单元。例5-1中函数定义和声明部分的语句void message(char *s)中,char *s即是形式参数,函数调用的语句message(name)中的name即是实际参数。例如,定义一个函数, 用于求两个数中的大数,可写为:int max(int a,int b) /*定义函数max,定义a,b两个整型的形参*/if(ab) return a;else return b; 第一行定义整型函数max(),其返回的函数值是一个整数。定义两个整型形参为a,b。 a,b 的具体值是由主调函数在调用时通过实参传递过来的。在 中的函数体内,除形参外没有使用其它变量,因此只有语句而没有变量类型说明。在主函数调用如下:int max(int a,int b); /*声明函数max()*/void main()int x,y,z;printf(input two numbers:n);scanf(%d,%d,&x,&y);z=max(x,y); /*调用函数max(),实参x,y分别传值给形参a,b */printf(max=%d,z);程序执行中调用max()函数,并把x,y中的值传送给形参a,b。max()函数执行,a, b中较大的值将返回给变量z。最后由主函数输出z的值。5.5.5 函数变量作用范围C语言中的变量,按作用域范围可分为两种,即局部变量和全局变量。 1. 局部变量在函数中定义或说明的变量称为局部变量,也称为内部变量。其作用域仅限于函数内, 从定义点或说明点开始到函数的结束为止,离开该函数后再使用这种变量是非法的。例如: int f1(int x) /*定义局部变量x */ int y; /* 定义局部变量y */ main()int x,y; /*定义局部变量x,y */if(xy)int m,n; /* 定义局部变量m,n */ 在函数f1()内定义了两个局部变量,x为形参,y为一般变量。在 f1()的范围内x,y有效,或者说x,y变量的作用域限于f1()内。main()函数内定义的局部变量x,y,在main()函数范围内有效。注意,main()函数的内部变量x,y和函数f1()的内部变量x,y虽然同名,却是完全不相关的变量。它们的作用域不同,不产生冲突。f1()中定义的x,y作用域限于f1()内。main() 函数中定义的x,y的作用域限于main函数内。main()函数的if条件复合语句中还定义了两个局部变量m,n,它们的作用范围仅限于该复合语句内部。2. 全局变量全局变量也称为外部变量,它是在函数外部定义的变量。 它不属于哪一个函数,它属于一个源程序文件。全局变量定义在所有函数的外部,就是图5-4所示的类型定义说明部分。其作用范围是从该变量定义开始到程序结束。在同一源文件中,允许全局变量和局部变量同名。在局部变量的作用域内,全局变量不起作用。例如: int a,b; /*定义全局变量a,b */int f1(int x) /*定义局部变量x */ int f2(int a) /*定义局部变量a */ main() 在所有函数外部定义了全局变量a,b,它们的作用范围应该是其后的所有函数,包括f1(),f2(),main()。但是由于在f2()中定义了局部变量a,因此在f2()中全局变量a不起作用。如例5-3中,由于C语言规定函数返回值只有一个,但是题目要求函数计算体积及三个面的面积,需要返回4个数据。当需要增加函数的返回数据时,用外部变量是一种很好的方式。例5-3中,如不使用全局变量,在主函数中就不可能取得v,s1,s2,s3四个值。而采用了全局变量,在函数count()中求得的s1,s2,s3的值在main()函数中仍然有效。因此全局变量是实现函数之间数据通讯的有效手段。5.5.5 指针和数组作为函数参数1. 指针作为函数参数例5-4如果不用指针,直接传递参数,代码如下#include void swap(int a,int b); /*函数声明*/void main()int x,y; x=10; y=20;printf(Before swapping:x=%d y=%dn,x,y);swap(x,y); /*调用函数*/printf(After swapping:x=%d y=%dn,x,y);void swap(int a,int b) /*定义函数*/ int t;t=a;a=b;b=t;运行结果如下:Before swapping:x=10 y=20After swapping:x=10 y=20为什么调用swap函数没有实现变量x,y的交换呢?通过图5-5所示的函数调用的执行过程,我们可以了解不能实现交换的原因。102010201020102010201020xyxyxyxymain函数swap函数abababab图5-5 参数传递过程(a)调用前 (b)调用时 (c)执行swap函数 (d)调用结束返回通过图5-3可以发现,C语言中的实参给形参传值是一种单向的“值传递”。当实参为变量时,函数调用时仅仅是将实参变量的值复制了一份交给形参,形参与对应实参的存储空间完全不同,在函数调用过程中对形参的改变,根本不会影响到实参的值。那么为什么例5-4中采用指针作为参数就能够实现互换呢?当swap函数中使用两个类型为整型的指针变量a和b作为形参,main函数中调用swap时,将两个整型变量x和y的地址 &x和 &y作为实参传递给形参a和b,调用过程中参数传递情况如图5-6所示。1020102010201020&x&y&x&yxyxyxyxymain函数swap函数abababab图5-6 指针变量作为参数的传递过程(a)调用前 (b)调用时 (c)执行swap函数 (d)调用结束返回指针变量作为形参时,参数传递的形式仍然为值传递。如图5-6所示,调用函数时,形参和对应的实参占据着不同的存储空间,但是形参存储空间中存放的不是实参的值,而是对应实参的地址。因此在函数调用的过程中,通过a,b对main函数中的变量x和y的间接访问,交换了他们的值。当函数调用完毕后,形参的存储空间仍然被收回,但此时变量x和y的存储空间已经保留了改变后的值。因此,编程时使用指针作为函数的形式参数,在函数调用参数传递的时候,函数间传递的不是变量的值,而是变量的地址。这样能够间接的访问实际参数。2. 数组作为函数参数数组作为函数的参数在C语言中应用非常广泛,当实现函数功能需要获取一批相关数据作为原始信息时,常常用数组作为参数。我们现在学习数组所有元素作为一个整体进行参数传递的问题,至于单个数组元素作为实参的情况,与变量作为实参相同,此处不再具体讨论。一维数组作为形参的定义形式为:类型名 形参数组名 不用指定元素个数,但方括号不可缺少。如例5-5中,sort函数定义的时候,使用了两个形参,定义形式为:void sort(int a,int n),其中数组形参采用了int a的形式。调用使用数组参数的函数时,实参数组应与对应的形参数组类型一致。调用时,实参数组不需要指定元素个数,也不需要加方括号,直接引用数组名就可以了。如例5-5中,调用sort函数使用语句sort(x,10),直接引用数组名x代表数组。下面来分析一下数组参数的传递过程。通过前面的学习,我们知道数组对应着内存中一块连续的区域,数组名表示这块区域的起始地址,即数组的首地址。当把实参数组名作为参数进行传递时,实际上是将实参数组的首地址传递给了形参数组,于是形参数组也就对应着该首地址开始的一块连续的存储区域,这样就使形参数组和实参数组对应同一块内存区域(如图5-7所示)。首地址12345678910实参数组xx0x1x2x3x4x5x6x7x8x0形参数组aa0a1a2a3a4a5a6a7a8a0图5-7 数组参数传递由于数组作为函数的参数时,形参数组和实参数组对应同一块内存区域,所以函数调用时,形参数组中各元素的值如果发生变化会使实参数组元素的值同时发生变化。5.5.7 函数的嵌套和递归调用1. 函数的嵌套调用函数的嵌套调用是指在调用一个函数的过程中,同时又调用了其他函数。在整个调用与别调用的过程中,每个函数从定义位置上讲是平行和独立的,不允许出现一个函数内部定义另一个函数的情况。例如: int f1( ) /*定义函数f1( ) */ int f2( ) /*定义函数f2( ) */ f1(); /* f2( ) 中调用函数f1()*/ main()f2(); /* main( )函数中调用函数f2()*/ 函数的嵌套调用如图5-8所示。图5-8 函数的嵌套调用2. 函数的递归调用函数在执行过程中直接或间接调用自身,称为函数的递归调用。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层。为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回,如例5-7中的if(n=0|n=1)f=1。5.5 练习(一)单选题1、完整的C源程序必须包括的函数是:( )Amain函数和一个以上的其他函数 Bmain函数C任意一个函数 D库函数2、返回值为void的函数,其含义是:( )A函数被调用后,函数不返回 B函数返回值为整型 C函数没有返回值 3、以下叙述中正确的是:( )AC语言程序的函数中必须有return语句 B在C语言程序中,函数的类型必须显式C在函数中,return语句必须放在函数体的最后Dreturn 语句中的表达式的类型应该与函数的类型赋值兼容4、函数的实参,不能是:( )A变量 B常量 C语句 D函数调用的表达式5、在C语言程序中( )A

温馨提示

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

评论

0/150

提交评论