Presentation is loading. Please wait.

Presentation is loading. Please wait.

第7章 函 数 本章要点: C语言程序结构和特点 函数的定义 函数的返回值与函数的类型 函数的调用及参数的传递关系 函数的嵌套与递归

Similar presentations


Presentation on theme: "第7章 函 数 本章要点: C语言程序结构和特点 函数的定义 函数的返回值与函数的类型 函数的调用及参数的传递关系 函数的嵌套与递归"— Presentation transcript:

1 第7章 函 数 本章要点: C语言程序结构和特点 函数的定义 函数的返回值与函数的类型 函数的调用及参数的传递关系 函数的嵌套与递归
第7章 函 数 本章要点: C语言程序结构和特点 函数的定义 函数的返回值与函数的类型 函数的调用及参数的传递关系 函数的嵌套与递归 全局变量和局部变量的概念 变量的存储类别 学习方法建议:   学习本章内容时,应重点掌握函数的定义和使用方法,学会函数的调用以及参数的传递关系。要求从阅读程序开始,逐步掌握函数编程的思路,并仿照例题练习编写程序、上机调试,真正掌握结构化程序的设计。函数的递归调用是本章的难点。

2 7.1 引例 1.问题描述——求函数值 求y = (f (x))3 + (f (x))2 + f (x) + 6的值,其中f (x) = x2 + 3x - 1,x为实数。 2.引例分析 此程序可定义三个函数,一个是f函数,功能是用于求x2 + 3x – 1的值,一个是fadd函数,该函数嵌套调用f函数,用于求y的值。第三个函数就是主函数,用来输入x的值,并输出y的值。

3 3.程序代码 #include "stdio.h" double fadd (double); /* 函数声明*/
double f(double); /* 函数声明*/ main( ) { double x,y; printf("Please Enter x:"); scanf("%lf",&x); /*输入x值*/ y=fadd(x); /*调用fadd(x)函数*/ printf("y = %6.3f \n",y); } /*输出y值*/ double fadd(double x) /*定义函数y = (f (x))3 + (f (x))2 + f (x) + 6*/ { double ftemp,y; ftemp=f (x); /*调用f (x)函数*/ y=ftemp*ftemp*ftemp+ftemp*ftemp+ftemp+6; /*计算y值*/ return y; } /*返回函数值*/ double f (double x) /*定义函数f (x) = x2 + 3x - 1*/ { double y; y=x*x+3*x-1; return y; } /*返回函数值*/

4   7.2 函数的定义与调用 函数的定义 任何函数(包括主函数main())都是由函数说明和函数体两部分组成。根据函数是否需要参数,可将函数分为无参函数和有参函数两种。 1. 无参函数的一般形式 函数类型 函数名( ) { 说明语句部分; 可执行语句部分; } 2. 有参函数的一般形式 函数类型 函数名( 数据类型 参数1[,数据类型 参数2…] ) 可执行语句部分;}

5 【例7.1】 定义一个函数,用于求两个数中的大数。
#include "stdio.h" int max(int n1, int n2) /*定义一个函数max()*/ { return (n1>n2?n1:n2); } main() { int max(int n1, int n2); /*函数说明*/ int num1,num2; printf("input two numbers:\n"); scanf("%d%d", &num1, &num2); printf("max=%d\n", max(num1,num2)); }

6 3. 空函数的定义 既无参数、函数体又为空的函数。其一般形式为: [函数类型] 函数名() { } 说明: (1)函数类型:用于指定函数带回来的值的类型,可以是任何有效类型。函数类型可以省略,则系统默认为int型,这时函数返回一个整数值。当函数无返回值时函数类型一般应写成void,称为无类型或空类型。 (2)参数表:它是一个用逗号分隔的变量说明表,参数表中的参数称为“形式参数”,简称“形参” 。形参用于主调函数和被调用函数之间进行数据传递,即当函数被调用时,形参接收实参传过来的值。 参数表的定义形式如下: 类型标识符 形式参数1,类型标识符 形式参数2,…… 例如:float area(float a,float b,float c) (3)可以定义空函数,即形式参数和函数体均为空。调用此函数时,不做任何工作,只是表明这里需要调用一个函数。

7 7.2.2 函数的返回值与函数类型 1. 函数返回值与return语句 return语句的一般格式为: return ( 返回值表达式 );
  函数的返回值与函数类型 1. 函数返回值与return语句 return语句的一般格式为: return ( 返回值表达式 ); 功能:返回调用函数,并将“返回值表达式”的值带给调用函数。 说明: (1)一个函数中可以有一个或多个return语句,当执行到某个return语句时,程序的控制流程将返回到主调函数,并将return语句中表达式的值作为函数值带回。 (2)若函数体内没有return语句,则一直执行到函数体末尾的“}”为止,然后返回到主调函数,这时也会有一个不确定的值被带回到主调函数。若不需要带回函数值,一般可将函数定义为void类型。 (3)return语句中表达式的类型应与函数类型一致,若不一致时,以函数类型为准。 2. 函数类型 函数类型与return语句返回值的类型一致。

8 7.2.3 对被调用函数的说明和函数原型 对被调用函数进行说明,其一般格式为:
  对被调用函数的说明和函数原型 对被调用函数进行说明,其一般格式为: 函数类型 函数名(数据类型[ 参数名1][, 数据类型[ 参数名2]…]); C语言规定,以下两种情况,可以省去对被调用函数的说明: (1)当被调用函数的函数定义出现在调用函数之前时。因为在调用之前,编译系统已经知道了被调用函数的函数类型、参数个数、类型和顺序。 (2)如果在所有函数定义之前,在函数外部(例如文件开始处)预先对各个函数进行了说明,则在调用函数中可缺省对被调用函数的说明。

9 7.2.4 函数的调用 1.函数调用 C语言中函数调用的一般形式为: 函数名([实际参数表]) 注意:
函数的调用 1.函数调用 C语言中函数调用的一般形式为: 函数名([实际参数表]) 注意: 实参的个数、类型和顺序,应该与被调用函数所要求的参数个数、类型和顺序一致,才能正确地进行数据传递。 2.函数调用方式 (1)函数表达式。函数作为表达式的一项,出现在表达式中,以函数返回值参与表达式的运算。这种方式要求函数是有返回值的。 例如:c=2*max(a,b); (2)函数语句。C语言中的函数可以只进行某些操作而不返回函数值,这时的函数调用可作为一条独立的语句。例如:max(a,b); (3)函数实参。函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的。 例如:n=max(a,max(b,c));其中max(b,c)是一次调用,它的值作为max另一次调用的实参。 (4)调用时实参与形参在类型必须匹配。

10 函数的形参与实参 函数的参数分为形参和实参两种,作用是实现数据传送。形参出现在函数定义中,只能在该函数体内使用。发生函数调用时,调用函数把实参的值复制1份,传送给被调用函数的形参,从而实现调用函数向被调用函数的数据传送。 关于形参与实参的说明: (1)实参可以是常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。 (2)形参变量只有在被调用时,才分配内存单元;调用结束时,即刻释放所分配的内存单元。 (3)实参对形参的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 (4)实参和形参占用不同的内存单元,即使同名也互不影响。

11 【例7.2】 实参对形参的数据传递。 #include "stdio.h" main() { void s(int n); /*函数说明*/ int n=100; /*定义实参n,并初始化*/ s(n); /*调用函数*/ printf("n_s=%d\n",n); /*输出调用后实参的值*/ } void s(int n) int i; printf("n_x=%d\n",n); /*输出改变前形参的值*/ for(i=n-1; i>=1; i--) n=n+i; /*改变形参的值*/ printf("n_x=%d\n",n); /*输出改变后形参的值*/

12 7.3 函数的的嵌套调用和递归调用 7.3.1 函数的嵌套调用
 7.3 函数的的嵌套调用和递归调用 函数的嵌套调用 函数的嵌套调用是指,在执行被调用函数时,被调用函数又调用了其他函数。其关系可表示如图所示。

13 【例7.3】 计算s=1k+2k+3k+……+N k 。 #define K 4 #define N 5 long f1(int n,int k) /*计算n的k次方*/ { long power=n; int i; for(i=1;i<k;i++) power *= n; return power; } long f2(int n,int k) /*计算1到n的k次方之累加和*/ { long sum=0; for(i=1;i<=n;i++) sum += f1(i, k); /*在函数f2()中调用函数f1()*/ return sum; } #include "stdio.h" main() { printf("Sum of %d powers of integers from 1 to %d = ",K,N); printf("%d\n",f2(N,K));}

14 所谓函数的递归调用是指,一个函数在它的函数体内,直接或间接地调用它自身。递归调用分为直接递归调用和间接递归调用两种,如图所示。
  函数的递归调用 所谓函数的递归调用是指,一个函数在它的函数体内,直接或间接地调用它自身。递归调用分为直接递归调用和间接递归调用两种,如图所示。

15 递归调用的过程可分为如下两个阶段: (1)递推阶段:将原问题不断转化为新问题,逐渐从未知向已知的方向推测,最终达到已知的条件,即递归结束条件。 (2)回归阶段:从已知条件出发,按递推的逆过程,逐一求值回归,最后到递推的起始处,完成回归。

16 【例7.4】 用递归法计算n!。 #include "stdio.h" long fact(int n) /*定义fact()函数,用于求n!*/ { long f; if(n>1) f=fact(n-1)*n; /*递归调用函数fact()*/ else f=1; return(f); } main() { int n; long y; printf("input a inteager number:\n"); scanf("%d",&n); y=fact (n); /*调用函数fact()*/ printf("%d!=%ld\n",n,y);

17   7.4 数组作为函数参数 数组元素作为函数参数 数组元素就是下标变量,与普通变量并无区别。数组元素只能用作函数实参,其用法与普通变量完全相同。在发生函数调用时,把数组元素的值传送给形参,实现单向值传送。 【例7.5】 写一函数,统计字符串中字母的个数。 #include "stdio.h" int isalp(char c) { if (c>='a'&&c<='z'||c>='A'&&c<='Z') /*判断是否为字母*/ return(1); /*返回真值1*/ else return(0); /*返回假值0*/ } main() { int i,num=0; char str[255]; printf("Input a string:\n "); gets(str); for(i=0;str[i]!='\0';i++) if(isalp(str[i])) num++;/*循环调用函数,若返回值为真,字母个数+1*/ puts(str); printf("num=%d\n",num);

18 数组名作为函数的形参和实参 数组名作函数参数时,既可以作形参,也可以作实参。而且形参和相对应的实参都必须是类型相同的数组(或指向数组的指针变量),都必须有明确的数组说明。 【例7.6】 已知某个学生5门课程的成绩,求平均成绩。 #include "stdio.h" float aver(float a[ ]) /*求平均值函数*/ { int i; float av,s=a[0]; for(i=1;i<5;i++) s+=a[i]; av=s/5; return av;} main() { float sco[5],av; int i; printf("\ninput 5 scores:\n"); for(i=0;i<5;i++) scanf("%f",&sco[i]); av=aver(sco); /*调用函数,实参为一数组名*/ printf("average score is %5.2f\n",av); }

19 } /*a,b,c作用域:仅限于函数f1()中*/ int f2(int x) /*函数f2*/ { int y,z;
  7.5 局部变量与全局变量 局部变量 在一个函数内部或一个复合语句内定义的变量称为局部变量,它只在本函数范围或该复合语句内有效,即只有在本函数内或本复合语句内才能使用它们,离开该范围是不能使用这些变量的。例如: int f1(int a) /*函数f1*/ { int b,c; } /*a,b,c作用域:仅限于函数f1()中*/ int f2(int x) /*函数f2*/ { int y,z; } /*x,y,z作用域:仅限于函数f2()中*/ main() { int m,n; } /*m,n作用域:仅限于函数main()中*/

20 7.5.2 全局变量 在函数外部定义的变量,它的作用域是:从定义变量的位置开始,到本文件结束。外部变量可被作用域内的所有函数直接引用。
全局变量   在函数外部定义的变量,它的作用域是:从定义变量的位置开始,到本文件结束。外部变量可被作用域内的所有函数直接引用。 例如: int x,y; /* 全局变量*/ float f1(int a) {… } float a,b; /* 全局变量*/ int f2(int c) { int z; } main() { int m,n;

21 【例7.7】 分析下面程序,写出运行结果。 int n=12; /* 定义全局变量n */ #include "stdio.h" main( ) { int n=5; /* 定义局部变量n */ printf("main Public n = %d \n",n); /* 局部变量n有效 */ fun1( ); fun2( ); } fun1( ) { printf("fun1 Public n = %d \n",n); /* 全局变量n有效 */ n++; /* 全局变量n有效 */ } fun2( ) { printf("fun2 Public n = %d \n",n); /* 全局变量n有效 */ { int n; /* 定义局部变量n */ for(n=1; n<3; n++) /* 局部变量n有效 */ printf("fun2 Local n = %d \n",n); /* 局部变量n有效 */ n++; /* 全局变量n有效 */ printf("fun2 Public n = %d \n",n); /* 全局变量n有效 */ }

22 7.6 变量的动态存储与静态存储简介   C语言对变量的存储类型说明有四种:自动变量(auto)、寄存器变量(register)、外部变量(extern)、静态变量(static)。 静态变量 定义格式: static 数据类型 变量表; 注意: 静态变量属于静态存储。在程序执行过程中,即使所在函数调用结束也不释放。换句话说,在程序执行期间,静态变量始终存在。 定义静态变量但不初始化,则自动赋以"0"(整型和实型)或'\0'(字符型);且每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值。 当需要保留函数上一次调用结束时的值或者变量只被引用而不改变其值时,才使用静态变量。

23 7.6.2 自动变量 定义格式:[auto] 数据类型 变量表; 注意:
自动变量 定义格式:[auto] 数据类型 变量表; 注意: 自动变量属于动态存储方式。在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束就释放。 在复合语句中定义的自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,否则将引起错误。 定义动态变量而不初始化,则其值是不确定的。如果初始化,则赋初值操作是在调用时进行的,且每次调用都要重新赋一次初值。 由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名。

24 【例7.8】 自动变量与静态变量的存储特性。 #include "stdio.h" void f() { int a=0; /*自动变量:每次调用都重新初始化*/ static int b=0; /*静态变量:只初始化1次*/ printf("a=%d,b=%d\n",a, b); ++a; ++b; } main() { int i; for(i=0; i<4; i++) f();

25 寄存器变量 一般情况下,变量的值都是存储在内存中的。为提高执行效率,C语言允许将局部变量的值存放到寄存器中,这种变量就称为寄存器变量。其定义格式为: register 数据类型 变量表; 注意: 只有局部变量才能定义成寄存器变量,即全局变量不行。 允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。 外部变量 外部变量属于静态存储方式。其定义格式为: extern 数据类型 外部变量表;

26 上机实验

27 一、实验目的 1.掌握函数的定义和调用; 2.掌握参数的传递关系。

28 二、实验内容 1.验证性实验 1)分析下面程序的输出结果,然后上机验证。 #include "stdio.h"
#include "math.h" void fun(); void main() { fun( ); } void fun( ) int x=0; static int y=0; x=x+1; y=y+1; printf("x=%d,y=%d\n",x,y);

29 2)下面程序是希望计算两个数的平均值,写出程序的预期结果,并上机验证。看看与预期的是否相同,若不同应当如何修改。
#include "stdio.h" double aver(int,int ); /*函数说明*/ main( ) { int a,b; double v; a=10;b=11; v=aver(a,b); /*函数调用*/ printf("%lf\n",v); } double aver(int x,int y) /*函数定义*/ double z; z=(x+y)/2; return z;

30 2.设计性实验 1)写一函数,使输入的一个字符串按反序存放,请将程序补充完整。 #include "stdio.h" #define N 5 void f(char zx[]) /*形参为数组*/ { int i,k; char fx[N]; printf("\nzx[%d]=%s\t",N, __①__);/*输出由主函数传递过来的正序数组*/ printf("fx[%d]=",N); for(k=0,i=N-1;i>=0;k__②__,i__③__) { fx[k]=zx[i]; printf("%c",fx[k]);} /*输出反序数组*/ } main() { int i; char zx[N]; printf("input a string:"); scanf("%s",zx); f(zx); /*调用f()函数,数组名作为函数的实际参数*/

31 2)产生3个小于10的随机数,计算他们阶乘的和;编写函数实现阶乘。例如:6!+0!+2!=723,请将程序补充完整。(提示:小于10随机函数为rand()%10)
#include "stdlib.h" #include "stdio.h" int f(int m) /*计算阶乘的函数*/ { int i,jc=1; for(i=1;i<=__①__;i++) jc*=i; return jc; } main() { int i,a[3],s=0; for(i=0;i<3;i++) { a[i]=(rand()%10); /*将3个随机产生的数据送入数组*/ s+=f(__②__); /*调用阶乘函数,并累加其返回值*/ } for(i=0;i<3;i++) /*按要求的格式输出*/ printf("%d!+",a[i]); printf("__③__=%d",s); /*去掉最后的+号*/

32 3)编写2个函数,分别求两个数的最大公约数和最小公倍数,请填空。
#include "stdio.h" zdgys(int x,int y) /*最大公约数函数*/ { int r, t; if(x__①__y){t=x;x=y;y=t;} while(r!=0) /* r为x/y余数*/ { r=x%y; if (r__②__0) return __③__; x=y; y=r; }} zxgbs(int x,int y) /*最小公倍数函数*/ { return((x__④__y)/zdgys(x,y));/*在返回值表达式中调用zdgys()函数*/ } main() { int a,b; printf("input two numbers:\n"); scanf("%d%d",&a,&b); printf("maxgys=%d\tmingbs=%d",zdgys(a,b),zxgbs(a,b));/*调用函数*/

33 4)用递归算法,把一个整数的每一位数分解,并从低位到高位打印出来,一行一个数。例如:对整数765,输出: 5 6 7。请填空。
#include "stdio.h" void f(int x) { int i; i=x%__①__; /*取出x的个位的数赋值给i*/ printf("%d ",i); x/=__②__; /*将x的值缩小10倍并截尾取整*/ if(x>0&&i>0) f(x); /*递归调用f(x)函数*/ } main() int a; printf("input a:\n"); scanf("%d",&a); f(a); /*调用f()函数,将实参传递给形参*/

34 5)函数 fun 的功能是:计算正整数num的各位上的数字之积。例如,若输入:252,则输出应该是:20。若输入:202,则输出应该是:0。请填空。
#include "stdio.h" long fun (long num) { long k=1; do { k*=num%10 ; num__①__; } while(num) ; return (k) ; } main( ) long n ; scanf("%d",&n) ; printf("\n%ld\n",fun(n)) ;

35 6)请编写一个函数 void fun(int tt[M][N],int pp[N]),tt指向一个M行N列的二维数组,求出二维数组每列中最小元素,并依次放入pp所指一维数组中。
#include <stdio.h> #define M 3 #define N 4 /*求出二维数组每列中最小元素,并依次放入pp所指一维数组中*/ void fun ( int tt[M][N], int pp[N] ) { } main( ) { int t [ M ][ N ]={{22,45, 56,30 } ,{19,33, 45,38}, {20,22, 66,40}}; int p [ N ], i, j, k; printf ( "The original data is : \n" ); for( i=0; i<M; i++ ) { for( j=0; j<N; j++ ) printf ( "%6d", t[i][j] ); printf("\n"); } fun ( t, p ); printf( "\nThe result is:\n" ); for ( k = 0; k < N; k++ ) printf ( " %4d ", p[ k ] ); }

36 7)函数fun的功能是求出一个2*M整型二维数组中最大元素的值,请将程序补充完整。
#include <stdio.h> #define M 4 fun (int a[][M]) { int i, j, max=a[0][0]; for(i=0; i<2; i++) for(j=0; j<M; j++) if(__①__) max=a[i][j]; return max; } main( ) int arr[2][M]={5,8,3,45,76,-4,12,82} ; printf("max =%d\n", fun(arr)) ;

37 8)编写函数fun,函数功能是计算并输出给定数组(长度为9)中每相邻两个元素之平均值的平方根之和。例如,给定数组中的9个元素依次为12
8)编写函数fun,函数功能是计算并输出给定数组(长度为9)中每相邻两个元素之平均值的平方根之和。例如,给定数组中的9个元素依次为 ,输出应为:s= 。。 #include <stdio.h> #include <math.h> /*计算并输出给定数组(长度为9)中每相邻两个元素之平均值的平方根之和 */ double fun(double x[9]) { } main() { double s,a[9]={12.0,34.0,4.0,23.0,34.0,45.0,18.0,3.0,11.0}; int i; printf("\nThe original data is :\n"); for(i=0;i<9;i++)printf("%6.1f",a[i]); printf("\n\n"); s=fun(a); printf("s=%f\n\n",s);

38 9)请编写函数fun,其功能是计算:s= ln(1)+ln(2)+ln(3)+…+ln(m),s作为函数值返回。在C语言中可调用log(n)函数求ln(n)。log函数的引用说明是:double log(double x)。 例如,若m的值为:20,fun函数值为: 。 #include <math.h> #include <stdio.h> double fun( int m ) /*计算:s= ln(1)+ln(2)+ln(3)+…+ln(m) */ { } main() printf("%f\n", fun(20));

39 10)请编写函数fun,函数的功能是:实现B=A+A’,即把矩阵A加上A的转置,存放在矩阵B中。计算结果在main函数中输出。
#include <stdio.h> void fun ( int a[3][3], int b[3][3]) /* 矩阵的转置 */ { } main( ) /* 主程序 */ int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, t[3][3] ; int i, j ; fun(a, t) ; for (i = 0 ; i < 3 ; i++) for (j = 0 ; j < 3 ; j++) printf("%7d", t[i][j]) ; printf("\n") ;

40 11)请编写函数fun,函数的功能是:求小于形参n同时能被3与7整除的所有自然数之和的平方根,并作为函数值返回。
例如若n为1000时,程序输出应为:s= 。 #include <math.h> #include <stdio.h> double fun( int n) { } main() /* 主函数 */ printf("s =%f\n", fun ( 1000) );


Download ppt "第7章 函 数 本章要点: C语言程序结构和特点 函数的定义 函数的返回值与函数的类型 函数的调用及参数的传递关系 函数的嵌套与递归"

Similar presentations


Ads by Google