1、1,第6章 函数,6.1 C语言函数概述 6.2 函数的定义 6.3 函数的调用 6.4 函数的嵌套调用与递归调用 6.5 用数组做函数参数 6.6 局部变量和全局变量 6.7 变量的存储类别 6.8 C语言预处理,2,程序一般应分为若干个程序模块; 每个模块用来实现一个特定的功能; 用子程序实现模块的功能; 在C语言中子程序的作用是由函数完成的。,6.1 C语言函数概述,3,一个C源程序可由一个主函数和若干个函数组成; 主函数可以调用其他函数; 其他函数不能调用主函数; 其他函数也可互相调用; 同一个函数可以被一个或多个函数调用任意多次。,4,例:要求输出以下的结果。 * How do yo
2、u do! *,#include void main() printstar(); print_message(); printstar(); ,在输出中分别有2行“*”号,显然不必重复写这段代码,5,printstar() printf(“* * * * * * * * * *n”); ,print_message() printf(“How do you do !n”); ,6,说明: 1)一个C程序由多个源程序文件组成; 2)一个源程序文件是一个编译单位; 可分别编写,分别编译; 一个源文件由一个或多个函数组成; 3)C程序的执行从main函数开始; 调用其他函数后,流程回到main函数
3、; 并在main函数中结束整个程序的运行;,7,4)所有函数是平行的; (即在定义函数时是相互独立的) 函数不能嵌套定义; (即一个函数并不从属于另一个函数) 函数间可以互相调用; (但不能调用main函数),8,5)从用户的角度看,函数有两种: 标准函数(库函数) 由系统提供。 用户自定义的函数 用以解决用户的专门需求。,9,6)从函数的形式看,函数有两类: 无参函数 在调用无参函数时,主调函数不把数据传送给被调函数; 无参函数可以带回或不带回函数值。 有参函数 在调用有参函数时,在主调和被调函数间有数据传递。,10,C语言要求,在程序中用到的所有函数,必须“先定义,后使用” 指定函数名字、
4、函数返回值类型、(函数实现的功能)以及参数的个数与类型,将这些信息通知编译系统。,6.2 函数的定义,11,指定函数的名字,以便以后按名调用 指定函数类型,即函数返回值的类型 指定函数参数的名字和类型,以便在调用函数时向它们传递数据 指定函数的功能。这是最重要的,这是在函数体中解决的,12,对于库函数,只需用#include指令把有关的头文件包含到本文件模块中即可; 需要在程序中自己定义库函数中没有提供的函数自定义函数;,13,无参函数的定义形式 类型标识符 函数名() 声明部分 语句 ,类型标识符: 规定函数值的类型。Void不需返回值 声明部分: 定义函数体内各变量及其类型。 语句: 完成
5、函数要处理的内容。,6.2.1 定义函数的一般形式,14,2. 有参函数定义的一般形式 类型标识符 函数名(形式参数列表) 声明部分 语句 ,15,例: int max(int x,int y) int z ; z = x y ? x :y ; return(z); ,int表示函数值为整型,即返回的值是整型。,两个形式参数: 调用时,主调函数把实际参数的值传递给被调函数的形式参数x,y。,主调函数的实际参数可以是任意的变量名或整型数或表达式。,形参的意义是只代表:在被调函数中将有两个被传递过来的值。,形参可以理解为未被赋值的变量,直到主调函数把实参传来后,才相当于为此变量赋了值。,16,函数
6、体:包括声明和语句两部分,声明部分: 1)定义在函数体内要使用的变量; 2)对将要调用的函数作声明。,语句部分: 是用来求函数的值。,例: int max(int x,int y) int z ; z = x y ? X :y ; return(z); ,把 z 的值作为函数值返回到主调函数中。,函数头部:包括类型、名字和形参三部分,17,3. 可以有空函数 类型标识符 函数名( ) ,调用此函数时,什么也不执行。,18,4. 对形参的声明方式 不同版本的C语言可能要求不同。 推荐使用: int max(int x,int y),19,函数调用的一般形式,函数名(实参列表),6.3.1 函数调
7、用的一般形式,6.3 调用函数,20,说明: (1)调用无参函数时,可以无实参名,但不能没有括号 (2)调用有参函数时,若实参个数多于1个,则各参数间用逗号分开。 (3)实参应与形参个数相等,最好是类型一致。 (4)实参与形参按顺序对应,一一传递数据。 (5)注意对实参的求值顺序,有自左向右或自右向左,21,例: void main( ) int f(int a,int b); int i=2,p; p=f( i ,+i ); printf(“%d”,p); ,运行结果为-1或0,int f(int a,int b) int c; if (ab) c=1; else if(a=b) c=0;
8、else c= - 1; return(c); ,是函数本身存在对参数的求值顺序问题; 同样,若函数中的参数是某种表达式,也有求值顺序问题。,22,从函数出现在程序中的位置看,有3种函数调用方式: 函数语句 把函数作为一个语句。 例如: printstar() ; 一般作为语句时,只要求函数完成一定的操作即可,不要求返回值。,函数调用的方式,23,2. 函数表达式 函数出现在一个表达式中,此时的表达式称为函数表达式。 例如: c=2*max(a,b) 函数要有返回值,以参加表达式的运算。,24,3. 函数参数 函数调用作为一个实参。 例如: m=max(a,max(b,c);,其中max(b,
9、c)是一次函数调用,它的值又作为max另一次调用的实参。,例如: printf(“%d”,max(a,b); 函数调用作为函数的参数,实际上也是函数表达式调用的另一种形式。,25,1.形式参数和实际参数,形式参数: 定义函数时,函数名后括号内的“变量名”称为形式参数; 实际参数: 主调函数中函数名后括号内的“参数”称为实际参数。,6.2.2 函数参数与返回值数据传递,26,2. 实参和形参间的数据传递 在调用函数过程中,系统会把实参的值传递给被调用函数的形参,或者说,形参从实参得到一个值 该值在函数被调用期间有效,可以参加被调函数中的运算,27,例6.1 求和。 解题思路: (1)函数名应是见
10、名知意,如:add (2)由于给定的两个数是整数,返回主调函数的 值(即和)应该是整型 (3)add函数应当有两个参数,以便从主函数接收 两个整数,因此参数的类型应当是整型,28,函数调用过程中,两个函数会发生数据联系,#include void main() int a,b,c; scanf(“%d%d”, c = add(a,b); printf(“%d”,c);,add(int x,int y) int z ; z = x + y ; return(z);,int add(int x,int y);,29,关于形参和实参的5点说明: 1)实参可以是常量、变量或表达式, 但实参必须有确定的
11、值。 在调用时把实参的值传给形参。 2)形参是在定义函数时指定的。 函数未被调用前,不占内存单元。 调用结束后,所占单元立即被释放。,30,3)形参必须指定类型。 (建议使用上述例子中的方式) 4)实参应与形参的类型相同或赋值兼容。,类型转换时:向形参的类型转换。 实参类型低于形参类型,按2.6.4的规则转换。 实参类型高于形参类型,则强制向形参类型转换,31,例:实参类型高于形参 max(int x,int y) int z; printf(“%d %dn“,x,y); z= x y ? x+1 : y+1 ; return(z); ,void main( ) float w; float
12、a=9.5,b=7.3; w=max(a,b); printf(“%f%f%f“,w,a,b); ,32,5)实参对形参进行的是“值”传递。 即只传参数的值,不传参数的名。 传递是单向的,不能回传。 形参的值发生改变,不会改变主调函数的实参的值,33,void swap(int x,int y) int temp; temp=x;x=y;y=temp; ,int main() int i=2,j=3; printf(“i=%d,j=%d”,i,j); swap(i,j); printf(“i=%d,j=%d”,i,j);,交换前:i=2,j=3,交换后:i=2,j=3,例6.2 交换变量的值,
13、34,通过函数调用使主调函数得到一个确定的值, 这就是函数的返回值。,函数的返回值,35,说明: (1)函数的返回值是通过函数中的return 语句获得的。,1)不需要返回值时,可以没有renturn语句。 2)return z 与 return(z) 作用相同。 3)return 后面的值可以是表达式。,36,(2)函数值的类型 既然函数有返回值,此值必属于某一个确定的类型。,1)应当在定义函数时指定函数值的类型; 2)省缺时认为是整型。 3)定义函数的类型应尽量与return语句的表达式类型一致。,int add(float x,float y),37,(3)若函数值的类型与return的
14、表达式的类型不同,则:,1)以函数的类型为准。即由函数的类型决定返回值的类型; 2)对数值型数据,可自动进行类型转换。,int add(float x,float y) float z; z=x+y; return(z); ,38,例6.3 返回值类型与函数类型不同。 void main( ) int max(float x,float y); float a=7.3,b=9.5; int c; c=max(a,b); printf(“%d”,c); ,max(float x,float y) float z; z=xy?x:y; return(z); ,高类型向低类型转换,输出9,39,(4
15、)被调函数中没有return 语句也是合法的。 函数同样可以带回返回值,只是此值是不确定的。 使用void(无类型或空类型)确保函数不带回任何值。,40,例如: void main( ) int a,b,c; a=printstar(); printf(“n”); b=print_message(); printf(“n”); c=printstar(); printf(“n”); printf(“%d,%d,%d”,a,b,c); ,printstar() printf(“* * * * * * * *”); ,print_message() printf(“How do you do!”)
16、; ,无return语句,41,(5)若想明确要求不带回返回值,使用void把函数定义为“无类型”(或称空类型)。 例如:void printstar() void print_message() ,不允许再使用: a=printstar(); b=print_message() 此时禁止使用返回值,42,6.3.2 对被调用函数的声明和函数原型 在一个函数中调用另一个函数,需要具备以下3个条件:,43,(1)被调用函数必须是一个已经存在的函数。 (2)使用库函数时,应在文件头加: #include 命令。 常用的有输入输出库函数:stdio.h 数学库函数 :math.h 字符处理函数 :
17、string.h (3)使用用户自定义的函数时,一般应在主调函数中对被调函数做声明。,44,所谓声明: 就是向编译系统说明将要调用此函数,并把有关信息通知编译系统。 信息包括: 函数名、函数类型、形参类型、形参个数、形参顺序,45,声明方法一: 在主调函数的声明部分进行声明,float add(float x,float y) float z; z=x+y; return(z);,对函数的声明,例: 对被调用的函数作声明 void main() float a,b,c; scanf(“%f,%f”,对函数的定义,float add(float x,float y) ;,46,对函数的定义: 是
18、指对函数功能的确立。 包括:函数名、函数的类型、形参及类型、函数体。 对函数的声明: 其作用是把函数名、函数类型以及形参类型、个数和顺序通知编译系统,使之在调用时按此对照检查。,47,当没有声明时: 由于编译是从上到下逐行进行的。当编译进行到调用函数的语句时,编译系统无法知道add是否为函数名,也无法判断实参的类型和个数是否正确。从而无法进行正确性检查。,48,函数原型: 函数的声明称为函数原型。 一般形式为: 函数类型 函数名(参数类型1,参数类型2,); 例如: float add(float,float);,49,声明的形式: 显式声明: 1)声明时应保证函数原型与函数首部写法一致。 2
19、)调用时,函数名、实参个数和顺序与原型相同。 3)实参类型与原型中的形参类型赋值兼容。,50,隐式声明: 1)编译系统把第一次遇到的该函数的形式作为声明看待,并默认为int型。(在VC中不允许) 2)把被调函数写在主调函数前面,可以不加声明。,float add(float x,float y) float z; z=x+y; return(z);,void main() float a,b,c; scanf(“%f,%f”, ,51,声明方法二: 在函数外作声明: 在函数外部作了函数声明后,各主调函数中可不再作声明。,52,char letter(char,char); float f(fl
20、oat,float); int i(float,float);,char letter(char c1,char c2) ,float f(float x,float y) ,int i(float j,float k) ,void main() ,53,54,6.4.1 函数的嵌套调用 关于嵌套定义的概念: 在定义一个函数时,其函数体内又包含了另一个完整的函数定义,这个内嵌的函数只能被包含它的函数调用,其他函数不能调用。,6.4 函数的嵌套调用和递归调用,55,C语言不能嵌套定义函数,但可以嵌套调用函数。 下图表示了两层嵌套调用。,56,在被调用的函数中又调用了其它函数。,57,例:输入4个
21、整数,找出其中最大的数。 用函数的嵌套调用来处理。,解题思路: main中调用max4函数,找4个数中最大者 max4中再调用max2,找两个数中的大者(标杆) max4中多次调用max2,可找4个数中的大者,然后把它作为函数值返回main函数 main函数中输出结果,58,#include int main() int max4(int a,int b,int c,int d); int a,b,c,d,max; printf(“4 interger numbers:“); scanf(“%d%d%d%d“, ,主函数:,对max4 函数声明,59,int max4(int a,int b,
22、int c,int d) int max2(int a,int b); int m; m=max2(a,b); m=max2(m,c); m=max2(m,d); return(m); ,max4函数:,对max2 函数声明,m作为标杆,60,int max2(int a,int b) if(a=b) return a; else return b; ,找a,b中较大者的max2函数,return(ab)?a:b);,61,int max4(int a,int b,int c,int d) int max2(int a,int b); int m; m=max2(a,b); m=max2(m,
23、c); m=max2(m,d); return(m); ,max4函数,m=max2(max2(a,b),c);,int max2(int a,int b) return(ab?a:b); ,62,int max4(int a,int b,int c,int d) int max2(int a,int b); int m; m=max2(a,b); m=max2(m,c); m=max2(m,d); return(m); ,max4函数,m=max2(max2(max2(a,b),c),d);,63,int max4(int a,int b,int c,int d) int max2(int
24、a,int b); int m; m=max2(a,b); m=max2(m,c); m=max2(m,d); return(m); ,max4函数,ruturn max2(max2(max2(a,b),c),d);,64,int max4(int a,int b,int c,int d) int max2(int a,int b); ruturn max2(max2(max2(a,b),c),d); ,int max2(int a,int b) return(ab?a:b); ,#include int main() max=max4(a,b,c,d); ,65,6.4.2 函数的递归调用,
25、递归的定义: 在调用一个函数的过程中,又直接或间接地调用了该函数本身。,66,定义一个函数f(x),例如: int f(int x) int y,z ; z=f(y) ; return(2*z) ; ,在本函数中又调用了本函数。,67,直接调用,间接调用,68,注意: 1)递归调用应为有限次数的、可终止的。 2)用 if 语句控制在某一条件成立时继续执行递归调用,否则不再继续。,69,例6.7 用递归调用方法求 n! 可用两种方法求n! 递推方法: 从一个已知的事实出发,按一定规律推出下一个事实,再从这个新的已知事实出发,向下再推出一个新的事实。,即从1开始,乘2,再乘3一直乘到 n,70,2
26、)递归方法: 分为回推和递推两个阶段。,即:5!= 5x4! 而 4!= 4x3! 1!= 1 可用递归公式表示为: 1 (n=0,1) n!= n*(n-1)! (n1),71,#include void main() int n; float y; scanf(“%d”, ,72,float fac(int n) float f; if(n0) printf(“n0,错误”); f= -1; else if(n=0|n=1) f=1; else f=n*fac(n-1); return(f); ,73,f=fac(5-1)*n f=fac(4-1)*n f=fac(3-1)*n f=fac
27、(2-1)*n f=fac(1),f=1*2*3*4*5 f=1*2*3*4 f=1*2*3 f=1*2 f=1,74,例: 递归调用,第一阶段(回推) 由第n 人 一直推到 第1人,第二阶段(递推) 由第 1 人一直推到第 n 人,age(5)=age(4)+2 age(4)=age(3)+2 age(3)=age(2)+2 age(2)=age(1)+2 age(1)=10,75,76,可用模型表述为: age(n)=10 (n=1) age(n-1)+2 (n1),将第n个人的年龄表示为第(n-1)人年龄的函数。,77,void main() printf(“%d”,age(5); ,用
28、一个函数来描述递归过程: age(int n) int c ; if(n=1) c=10 ; else c=age(n-1)+2 ; return(c) ;,78,例6.8 (略) 例:输出Fibonacci数列第n项的值。 F1 =1 (n=1) F2 =1 (n=2) Fn =Fn-1 + Fn-2 (n3) 从公式的第三行我们可以直观地看出Fibonacci数列的递归性。,79,#include void main() unsigned long fib(int n); int n; scanf(“%d“, ,unsigned long fib(int n) if(n=1) return
29、 n; else return fib(n-1)+fib(n-2); ,运行输入:5 运行结果:5,80,程序分析函数fib的执行过程: fib(5)发现5不小于等于1,转去执行fib(n-1)+fib(n-2)。可表示为:fib(5-1)+fib(5-2);语句中首先调用fib(5-1)。注意,此时不调用fib(5-2)。,unsigned long fib(int n) if(n=1) return n; else return fib(n-1)+fib(n-2); ,重复上述过程直至fib(1)发现1等于1,于是程序执行return n语句,并把n的值1返回到调用fib(1)处,替代fi
30、b(2-1),使得return语句的表达式变成1+fib(2-2)+的形式。,显然此时应执行函数调用fib(2-2),其返回值为0,使得return语句的表达式变成1+0+。继续执行省略号()部分直至结束,fib(4)也会发现4不小于等于1,所以又在fib(4-1)+fib(4-2)语句中调用fib(3)。同样,此时亦不调用fib(4-2),当然也不去调用上次的fib(5-2)。,81,上述函数调用过程可表示为如下分解步骤: fib(5-1)+ fib(5-2) fib(4-1)+ fib(4-2)+ fib(5-2) fib(3-1)+ fib(3-2)+fib(4-2)+ fib(5-2)
31、 fib(2-1)+fib(2-2)+fib(3-2)+fib(4-2)+ fib(5-2) 由于fib(2-1)就是fib(1),而fib(1)的值是1,fib(0)的值为0,所以上式可以写成: 1 + 0 + 1 +fib(2-1)+fib(2-2)+fib(5-2) 1 + 0 + 1 + 1 + 0 +fib(3-1)+ fib(3-2) 1 + 0 + 1 + 1 + 0 +fib(2-1)+fib(2-2)+fib(3-2) 1 + 0 + 1 + 1 + 0 + 1 + 0 + 1 上面过程的最后一行的和是5,即Fibonacci数列第5项的值。,unsigned long fi
32、b(int n) if(n=1) return n; else return fib(n-1)+fib(n-2); ,82,可以看出,上述过程是逐步分解然后再逐步求值的过程。 逐步分解的过程是把函数从顶层fib(5)向底层fib(1)逐层调用,直到fib(1)为止。然后是逐步返回函数值,即从fib(1)的出口值逐步得到fib(5)的值。 我们把这样的函数调用方法称为递归调用,并把逐步分解的过程称为“回推”,把逐步得到返回值的过程称为“递推”。 对于数学中的归纳问题,在C程序中可以用递归函数来求解。使用递归函数可以使程序结构简单,但是递归深度太大会使系统开销成倍增长。另外,递归深度太大也不利于程
33、序员把握程序的执行过程。 大多数可以用递归方法求解的问题也可以用循环的方法求解。显然,在循环方法中,循环不能无限制地进行下去; 在递归方法中,回推的过程也不应无限制地进行下去,这两种方法都必须考虑设置程序控制结构的出口条件,如例中的if(n=1)就是出口条件。,83,例: Hanoi(汉诺)塔问题。 塔内有3个座A、B、C,开始时座上有64个盘子,盘子大小不等,大的在下,小的在上。 想把这64个盘子从座移到座,但规定每次只允许移动一个盘,且在移动过程中在3个座上都始终保持大盘在下,小盘在上。 在移动过程中可以利用B座。要求编程序输出移动一盘子的步骤。,84,85,解题思路: 要把64个盘子从A
34、座移动到C座,需要移动大约264 次盘子。一般人是不可能直接确定移动盘子的每一个具体步骤的。 老和尚会这样想:假如有另外一个和尚能有办法将上面63个盘子从一个座移到另一座。那么,问题就解决了。此时老和尚只需这样做:,86,解题思路: (1) 命令第2个和尚将63个盘子从A座移到B座 (2) 自己将1个盘子(最底下的、最大的盘子) 从A座移到C座 (3) 再命令第2个和尚将63个盘子从B座移到C座,87,A,B,C,将63个从A到B,第1个和尚的做法,88,A,B,C,将63个从A到B,第1个和尚的做法,89,A,B,C,将1个从A到C,第1个和尚的做法,90,A,B,C,将1个从A到C,第1个
35、和尚的做法,91,A,B,C,将63个从B到C,第1个和尚的做法,92,A,B,C,将63个从B到C,第1个和尚的做法,93,A,B,C,将62个从A到C,第2个和尚的做法,94,A,B,C,将62个从A到C,第2个和尚的做法,95,A,B,C,将1个从A到B,第2个和尚的做法,96,A,B,C,将1个从A到B,第2个和尚的做法,97,A,B,C,将62个从C到B,第2个和尚的做法,98,A,B,C,将62个从C到B,第2个和尚的做法,99,第3个和尚的做法 第4个和尚的做法 第5个和尚的做法 第6个和尚的做法 第7个和尚的做法 第63个和尚的做法,第64个和尚仅做:将1个从A移到C,100,
36、A,B,C,将3个盘子从A移到C的全过程,将2个盘子从A移到B,101,A,B,C,将3个盘子从A移到C的全过程,将2个盘子从A移到B,102,A,B,C,将1个盘子从A移到C,将3个盘子从A移到C的全过程,103,A,B,C,将3个盘子从A移到C的全过程,将1个盘子从A移到C,104,A,B,C,将3个盘子从A移到C的全过程,将2个盘子从B移到C,105,A,B,C,将3个盘子从A移到C的全过程,将2个盘子从B移到C,106,A,B,C,将2个盘子从A移到B的过程,将1个盘子从A移到C,107,A,B,C,将2个盘子从A移到B的过程,将1个盘子从A移到C,108,A,B,C,将2个盘子从A移
37、到B的过程,将1个盘子从A移到B,109,A,B,C,将2个盘子从A移到B的过程,将1个盘子从A移到B,110,A,B,C,将2个盘子从A移到B的过程,将1个盘子从C移到B,111,A,B,C,将2个盘子从A移到B的过程,将1个盘子从C移到B,112,A,B,C,将2个盘子从B移到C的过程,113,A,B,C,将2个盘子从B移到C的过程,114,A,B,C,将2个盘子从B移到C的过程,115,A,B,C,将2个盘子从B移到C的过程,116,由上面的分析可知:将n个盘子从A座移到C座可以分解为以下3个步骤: (1) 将A上n-1个盘借助C座先移到B座上 (2) 把A座上剩下的一个盘移到C座上 (
38、3) 将n-1个盘从B座借助于座移到C座上,117,可以将第(1)步和第(3)步表示为: 将“one”上n-1个盘移到“two”(借助“three”)。 在第(1)步和第(3)步中,one 、two、three和A、B、C的对应关系不同。 对第(1)步,对应关系是one对应A,two对应B,three对应C。 对第(3)步,对应关系是one对应B,two对应C,three对应A。,118,把上面3个步骤分成两类操作: (1) 将n-1个盘从一个座移到另一个座上(n1)。是大和尚让小和尚做的工作,它是一个递归的过程,即和尚将任务层层下放,直到第64个和尚为止。 (2) 将1个盘子从一个座上移到另
39、一座上。这是大和尚自己做的工作。,119,编写程序 用hanoi函数实现第1类操作(模拟小和尚的任务) 用move函数实现第2类操作(模拟大和尚自己移盘) 函数调用hanoi(n,one,two,three)表示将n个盘子从“one”座移到“three”座的过程(借助“two”座) 函数调用move(x,y)表示将1个盘子从x座移到y座的过程。x和y是代表A、B、C座之一,根据每次不同情况分别取A、B、C代入,120,#include void main() void hanoi(int n,char one, char two,char three); int m; printf(“the
40、number of diskes:“); scanf(“%d“, ,121,void hanoi(int n,char one,char two, char three) void move(char x,char y); if(n=1) move(one,three); else hanoi(n-1,one,three,two); move(one,three); hanoi(n-1,two,one,three); ,122,void move(char x,char y) printf(“%c%cn“,x,y); ,123,6.5.1 数组元素作函数实参,由于数组元素可以是表达式的组成部分
41、,因此元素可以作为实参,采用“值传送”,即单向传递方式“单向值传递”。,6.5 用数组做函数参数,124,解题思路: 定义数组a,用来存放10个数 设计函数max,用来求两个数中的大者 在主函数中定义变量m,初值为a0,每次调用max函数后的返回值存放在m中 用标杆法,依次将数组元素a1到a9与m比较,最后得到的m值就是10个数中的最大者,例6.9(略) 例:输入10个数,要求输出其中值最大的元素和该数是第几个数。,125,#include int main() int max(int x,int y); int a10,m,n,i; for(i=0;im) m=max(m,ai); n=i;
42、 printf(“largest is %dn“,m); printf(“%dn”,n+1);,定义形参时不能使用元素形式ai,int max(int x,int y) return(xy?x:y); ,数组元素作为实参 形参仍为变量,126,6.5.2 用一维数组名作函数参数,除了可以用数组元素作为函数(实)参数外,还可以用数组名作函数参数(包括实参和形参) 用数组元素作实参时,向形参变量传递的是数组元素的值 用数组名作函数实参时,向形参传递的是数组首元素的地址首地址,127,实参与形参都用数组名,例:用个一维数组存放10个学生的成绩, 求平均成绩。 void main() float av
43、erage(float array10); float score10 ; int i ,aver ; for(i=0;i10;i+) scanf(“%f”, ,数组名,数组名,128,float average(float array10) int i ; float aver , sum=array0 ; for(i=1 ; i10 ; i+) sum=sum+array i ; aver=sum/10 ; return(aver) ;,形式参数名,可任意,第个元素的值已经赋给sum,因此 i 从开始。,129,说明: )用数组名作函数参数,应在主调函数和被调函数中分别定义数组,例如arr
44、ay是形参数组名,score是实参数组名,分别在其所在函数中被定义,不能只在一方定义。 )实参数组与形参数组类型应一致。 )只把实参数组的首地址传给形参数组,因此scoren和arrayn指的是同一单元。 )不指定形参数组大小时,可在调用时另传一个参数来指定要处理数组元素的个数。,130,)重要说明: 由于不是把数组的值传给形参,而是把实参数组的首地址传给形参数组; 因此:两个数组就共同占有同一段内存单元; 显然:形参数组中各元素的值如果发生变化, 也会使实参数组元素的值同时发生变化, 这与用变量作函数参数时不同; 这一特点可产生好的和坏的两方面的结果。,131,int main() int
45、a2=1,2; swap(a); printf(“a0=%dna1=%dn”,a0,a1); return 0; ,例6.10 交换元素的值。 #include void swap(int x) int z; z=x0;x0=x1;x1=z; ,132,例6.11和12 有两个班级,分别有35名和30名学生,调用一个average函数,分别求这两个班的学生的平均成绩。,解题思路: 需要解决怎样用同一个函数求两个不同长度的数组的平均值的问题 定义average函数时不指定数组的长度,在形参表中增加一个整型变量i 从主函数把数组实际长度从实参传递给形参i 这个i用来在average函数中控制循环的
46、次数 为简化,设两个班的学生数分别为5和10,133,#include int main() float average(float array ,int n); float score15=98.5,97,91.5,60,55; float score210=67.5,89.5,99,69.5, 77,89.5,76.5,54,60,99.5; printf(“%6.2fn”,average(score1,5); printf(“%6.2fn”,average(score2,10); return 0; ,134,float average(float array ,int n) int i
47、; float aver,sum=array0; for(i=1;in;i+) sum=sum+arrayi; aver=sum/n; return(aver); ,调用形式为average(score1,5)时,相当于score10,相当于score1i,相当于5,135,float average(float array ,int n) int i; float aver,sum=array0; for(i=1;in;i+) sum=sum+arrayi; aver=sum/n; return(aver); ,调用形式为average(score2,10)时,相当于score20,相当于score2i,相当于10,136,例6.13 用选择法对数组中10个整数按由小到大排序。,解题思路: 即先将10个数中最小的数与a0对换; 再将a1到a9中最小的数与a1对换 每比较一轮,找出一个未经排序的数中最小的一个 共比较9轮,137,a0 a1 a