480 likes | 637 Views
第 8 章 函数. 任课教师 : 张盈. 本章主要内容. C 语言程序的结构 函数的定义 函数的调用 函数的嵌套调用 递归函数 数组与函数 全局变量与. C 程序的结构由若干个 C 函数组成。 C 函数是 C 程序的组成部分,是由完成一特定任务的说明语句和执行语句组成的基本功能单元。 C 函数的功能相当于其它程序设计语言中的一个程序模块,或一个子程序。. 8.1 结构化程序设计语言 --- C 语言. main. a. b. c. g. h. d. e. f. k. l. i. j. 模块化程序示意图 :. 函数调用程序实例.
E N D
第8章 函数 任课教师: 张盈
本章主要内容 • C语言程序的结构 • 函数的定义 • 函数的调用 • 函数的嵌套调用 • 递归函数 • 数组与函数 • 全局变量与
C程序的结构由若干个C函数组成。 C函数是C程序的组成部分,是由完成一特定任务的说明语句和执行语句组成的基本功能单元。 C函数的功能相当于其它程序设计语言中的一个程序模块,或一个子程序。 8.1 结构化程序设计语言---C语言
main a b c g h d e f k l i j 模块化程序示意图:
函数调用程序实例 调用函数 main( ) { printstar(); print_message( ); printstar( ); } printstar( ) { printf(“**************\n”);} print_message( ) { printf(“how do you do!\n”);} 用户自定义函数
函数的分类(1) • 从使用角度分: 标准库函数:以程序库的形式直接提供给用户使用。 stdio.h……gets()、printf() math.h ……sin()、sqrt() 用户自定义函数:由用户自己建立定义。
函数的分类(2) • 从函数形式分: • 无参函数:调用函数时主函数不将数据传送给被调函数。用于完成特定功能的操作。 如:c=getchar( )…… • 有参函数:调用函数时在主调函数和被调函数之间有参数传递。 如:putchar(c)、puts(str)、……
函数说明 • 一个C程序是由一个或多个源文件组成,每个源文件由若干函数组成。 • C程序的执行从main函数开始,也从main函数终止。 • 源程序中所有的函数在结构上都是平行的,互相独立的。 • main函数可以调用其他函数,其他函数之间可以互相调用。
8.2.1 函数的定义(一) • 无参函数的特点:只完成某些动作,不进行参数传递。 • 无参函数的定义形式: 类型标识符 函数名( ) { 说明部分; 语句部分 }
【8.1】无参函数使用示例。 main( ) { printstar( ); printword( ); printstar( ); } printstar( ) /*定义无参函数printstar()*/ { printf("******************\n");} printword( ) /*定义无参函数printword()*/ { printf("This is an example\n");}
有参函数定义形式(一): 类型标识符 函数名(形式参数列表) 形式参数说明; { 说明部分; 语句部分; } int max(x,y) int x,y; { int z; z=(x>y)?x:y; return(z); } 函数的定义(二) 举例
int max( int x,int y) { int z; z=(x>y)?x:y; return(z); } 有参函数定义形式(二): 类型标识符 函数名(类型名 参数1,…,类型名 参数n) { 说明部分; 语句部分; } 函数的定义(二) 举例
有参函数定义说明: • “类型标识符”指的是函数计算结果的数据类型,即函数类型。 • “函数名”必须是合法的标识符,命名时尽可能使之“见名知意”。 • 参数的类型定义部分可在{ }外,也可在{ }内。 • 只在函数内部使用的变量,因为不参与主调函数与被调函数之间的参数传递,必须放在{ }内部的说明部分位置。
【8.2】求两数的最大值。注意函数的定义形式。【8.2】求两数的最大值。注意函数的定义形式。 main( ) { int a,b,c; scanf("%d%d",&a,&b); c=max(a,b); printf("max=%d\n",c); } int max(x,y) int x,y; { int z; z=(x>y)?x:y; return(z); }
8.2.2 函数参数 几个相关术语: • 函数调用:一个函数调用另一个函数。 • 主调函数、被调函数 • 有参函数:主调函数和被调函数之间有数据传递关系,被调函数即有参函数。 • 无参函数:主调函数和被调函数之间无数据传递关系,被调函数即无参函数。 • 举例
关于实参和形参 main( ) {int a,b,c; scanf("%d%d",&a,&b); c=max(a,b); printf("max=%d\n",c); } int max(int x,int y) { int z; z=(x>y)?x:y;return(z);} 实际参数 形式参数
8.2.3 函数的返回值 • 函数的返回值是通过return语句传递的。 • return语句的一般形式: return 表达式; return (表达式);
main() { int a,b,c; scanf(“%d%d”,&a,&b); c=max(a,b); printf(“max=%d\n”,c); } int max(x,y) int x,y; { int z; z=(x>y)?x:y; return(z); } return语句执行图示: 主调函数 被调函数
函数返回值的注意事项 • 返回值类型要与函数类型一致,且以函数类型为准。 • 函数类型缺省时,系统自动按整型处理。 • 例如: int max(int x,int y ) { return x*y;}
补充说明 • 一个函数中可以有若干个return语句,流程执行到哪里,就从哪里返回主调函数。 • 若函数体内没有return语句,则执行函数到末尾,然后返回主调函数。 • 当不需要返回值的时候,可以用void定义函数为空类型,表示无返回值。
8.3 函数的调用 • 8.3.1 函数调用的一般格式: 函数名(实参表); • 举例(设已建立max函数,为求最大值): …… main( ) { int x,y,z; scanf(“%d,%d”,&x,&y); z=max(x,y); …… }
8.3.2 函数调用中参数传递的两种方法 • 传值调用:函数调用中,采用赋值方式将实参的值传给形参。即单向调用。 • 传址调用:函数调用中,把实参的地址传给形参。在被调用函数中通过形参中的地址来访问调用函数中的实参。双向调用。
8.3.3 函数调用的三种方式 按照函数在程序中出现的位置来分; • 作为表达式出现在任何允许表达式出现的地方,参与运算。 如:a=sqrt(b); • 作为一条独立的语句完成特定的操作。 如:gets(string1); • 作为函数的参数被其他函数调用。 如:printf(“%s\n”,strcpy(str1,”Red rose”));
8.3.4 调用函数与被调函数的相对位置关系 • 如使用库函数,一般应在文件开头用: #include <……> …… • 函数调用遵循“先定义后调用”的原则。一般被调函数放在调用函数之前定义。 • 若被调函数在调用函数之后定义,就必须在调用函数中对被调函数加以如下说明: 类型名 被调函数名( );
【例8.12】 被调函数 在调用函 数之后出 现: main( ) { float sum( ); /*对被调函数的说明*/ float a,b,c; scanf("%f%f",&a,&b); c=sum(a,b); printf("sum=%f\n",c); } float sum(x,y) /*对函数sum进行定义*/ float x,y; { float z; z=x+y; return z; }
8.4 函数的嵌套调用 • C语言程序由函数构成。 • 函数与函数之间是平行的,独立的。 • 不允许在一个函数内部嵌套定义另一个函数;但允许在调用一个函数的过程中,又调用另一个函数。
函数a 函数b main函数 调用函数b 调用函数a 结束 函数的嵌套调用
8.5 递归函数 • 递归调用: 在调用一个函数的过程中又出现直接或间接的调用该函数本身,称为函数的递归调用。 注意: 递归结构构成了另外一种形如循环的结构。
递归函数设计举例:求n! • 算法描述: n!=1 × 2 × 3 × …… × (n-1)×n • 求积公式: 1 n=0 n ×(n-1)! n>0 f(n) =
5!的运算过程: ? 5! 120 5×4! 5×24 4×3! 4×6 3×2! 3×2 2×1 2×1! 1×0! 1×1 1
求n!递归源程序如下: n!递归程序源程序1/2 main( ) { int x; long facto( ); printf("Input a number:\n"); scanf("%d",&x); printf("The result is %ld",facto(x)); }
n!递归程序源程序2/2 long facto(n) int n; { long int z; if (n==0) z=1; else z=n*facto(n-1); return z; }
8.6 数组与函数 函数间传递数组数据的两种方法: • 值传递:将数组中的每个元素都作为一个参数来传递。 • 地址传递:通过地址传送方式将数组的首地址(如数组名)作为参数进行传递 。
8.6.1 数组元素作函数实参 • 数组元素(同简单变量)作函数实参,单向值传递,即“传值调用”方式。 • 【例8.17】用程序求出a数组中所有素数的和及平均值,函数isprime用来判断自变量是否素数。
源程序1/2 int isprime(int x) /*该函数判断是否素数*/ { int i; for (i=2;i<=x/2;i++) if (x%i==0) return (0); return (1); } main( ) { int i,a[10],sum=0,n=0; float aver; printf("Enter 10 numbers:\n"); for(i=0;i<10;i++)
源程序2/2 scanf("%d",&a[i]); printf("\n"); for(i=0;i<10;i++) if(isprime(a[i])==1) /*若a[i]素数*/ { printf("%d ",a[i]); sum+=a[i]; /*求素数和*/ n++; /*统计素数个数*/ } aver=sum/n; /*求素数平均值*/ printf("\nsum=%d,aver=%f\n",sum,aver); }
8.6.2 数组名作函数实参 • 形参和实参都采用数组名,传递是实参数组的起始地址,是地址传递方式。 • 【例8.18】求某学生10门课程成绩的平均分,课程成绩用数组存放。
【例8.18】 源程序1/2 数组名作形参 float average(b) float b[10]; { int i; float aver,sum=0; for (i=0;i<10;i++) sum+=b[i]; aver=sum/10; return(aver); }
源程序2/2 main( ) { float a[10],ave; int i; printf("Input 10 scores:\n"); for (i=0;i<10;i++) scanf("%f",&a[i]); printf("\n"); ave=average(a); printf("average score is %5.2f",ave); } 数组名作实参,传递的是实参数组的起始地址
使用数组名作函数实参说明 • 数组名表示数组元素存放的起始地址,可认为是地址常量。 • 数组名作实参,传递是数组地址,而非数组元素。 • 字符串常量作实参,传递的字符串常量的首地址而非字符内容。 • 用数组名作函数参数,必须在主调函数和被调函数中分别定义数组,并保证类型一致。
8.7.1 局部变量和全局变量 基本概念: • 变量的生命期 变量占用存储空间的时限 • 变量的作用域 在变量占用存储空间的时间内是否能够被引用,即变量作用的有效范围是全局的还是局部的。
局部变量 • 局部变量 在一个函数内部定义的变量(内部变量),它只在此函数范围内有效,在此函数以外不能被使用。 • 局部变量的作用域所在函数内部
局部变量举例。 a 、b、c有效范围 float f1(a) int a; { int b,c; …… } char f2(int x, int y) { int a,b; …… } main() { int m,n; …… } x、y、a 、b有效范围 m、n有效范围
局部变量使用说明: • 主函数main中定义的变量只在main函数中有效。 • 不同函数中可以使用同名变量,它们互不干扰。 • 形参也是局部变量。 • 在一个函数内部,可以在复合语句中定义变量,这些变量只在该复合语句中有效。这种复合语句称为“分程序”和“程序块”。
全局变量 • 在函数之外定义的变量是外部变量,外部变量是全局变量。全局变量可以为本文件中所有函数共用。 • 全局变量的有效范围为从定义变量的位置开始直到本源文件结束。 • 设置全局变量的作用是增加函数间数据联系的渠道。
全局变量举例。 int i,j; /*全局变量*/ float f1(a) int a; { int b,c; …… } float p,q; /*全局变量*/ char f2(int x, int y) { int a,b; …… } main() { int m,n; …… } 全局 变量 i、j 的作用 范围 p、q 的作用 范围
全局变量的使用说明 在程序设计中,应尽量避免使用全局变量。 • 全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。 • 如果在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用域范围内外部变量不起作用。 • 使函数的可靠性和通用性降低。 • 使用全局变量过多,会降低程序的清晰性。
作业: • 编程求下列的公式(m、n为整型变量): • 教材上本章习题程序(P172)1~8,任选3道。