c程序设计(谭浩强版)第七讲函数_第1页
c程序设计(谭浩强版)第七讲函数_第2页
c程序设计(谭浩强版)第七讲函数_第3页
c程序设计(谭浩强版)第七讲函数_第4页
c程序设计(谭浩强版)第七讲函数_第5页
已阅读5页,还剩94页未读 继续免费阅读

下载本文档

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

文档简介

1、第七章l 本章要点本章要点 函数的概念函数的概念 函数的定义与调用函数的定义与调用 函数的递归调用函数的递归调用 变量的作用域变量的作用域 函数的作用域函数的作用域程序设计的艺术 三国演义三国演义中有这样一段描写:中有这样一段描写:懿问曰:懿问曰:“孔明寝食及事之烦简若何?孔明寝食及事之烦简若何?”使者曰:使者曰:“丞相夙兴夜寐,罚二十以上皆亲览焉。所啖之食,丞相夙兴夜寐,罚二十以上皆亲览焉。所啖之食,日不过数升。日不过数升。”懿顾谓诸将曰:懿顾谓诸将曰:“孔明食少事烦,孔明食少事烦,其能久乎?其能久乎?”此话音落不久,诸葛亮果然病故于五丈原。此话音落不久,诸葛亮果然病故于五丈原。 “事无巨细

2、事无巨细”,“事必躬亲事必躬亲” 管理学的观点是极其排斥这种做法的,认为工作必管理学的观点是极其排斥这种做法的,认为工作必须分工,各司其职须分工,各司其职其中的思想,在程序设计里也适用其中的思想,在程序设计里也适用 假如不模块化 读多少行的程序能让你不头疼? main()当中能放多少行程序? 假如printf()函数由10行代码替换,那么你见过的程序会成什么样子? 如果所有代码都在main()当中,怎么团队合作? 如果代码都在一个文件中,怎么团队合作? C是模块化程序设计语言是模块化程序设计语言 源程序文件1预编译命令说明部分执行部分函数1函数n源程序文件i源程序文件nC程序C程序结构概述vo

3、id main() : x=x*x*x; y=y*y*y; z=z*z*z; ans1=x+y+z; a=a*a*a; b=b*b*b; c=c*c*c; ans2=a+b+c; :为什么使用函数重复多次的同一计算类型void main() : ans1=cube(x,y,z); ans2=cube(a,b,c); :int cube(int a,b,c) int ans; ans=(a*a*a)+(b*b*b)+(c*c*c); return ans;函数主程序ans函数可以把相对独立的某个功能抽象出来,使之成为程序中的一个独立实体。可以在同一个程序或其他程序中多次重复使用【例】编写一个儿童

4、算术能力测试软件main() char ans = y; clrscr( ); cover( ); /*调用软件封面显示函数*/ password( ); /*调用密码检查函数*/ while (ans =y| ans =Y) question( ); /*调用产生题目函数*/ answers( ); /*调用接受回答函数*/ marks( ); /*调用评分函数*/ results( ); /*调用结果显示函数*/ printf(“是否继续练习?(Y/N)n”); ans=getch ( ); printf(“谢谢使用,再见!”); 自定义函数为什么使用函数为什么使用函数【例二】编写一个儿童

5、算术能力测试软件main() char ans = y; clrscr( ); cover( ); /*调用软件封面显示函数*/ password( ); /*调用密码检查函数*/ while (ans =y| ans =Y) question( ); /*调用产生题目函数*/ answers( ); /*调用接受回答函数*/ marks( ); /*调用评分函数*/ results( ); /*调用结果显示函数*/ printf(是否继续练习?(Y/N)n); ans=getch ( ); printf(谢谢使用,再见!);/*定义所用函数*/cover() /*软件封面显示函数*/pass

6、word() /*密码检查函数*/question() /*产生题目函数*/answers() /*接受回答函数*/marks() /*评分函数*/results() /*结果显示函数*/ n 这些函数现在不编程或还不会编程,可先放空。n 可以多人合作,每人完成若干个函数(模块化)。n 可在另一个源程序文件中定义。Lets try l 如果把编程比做制造一台机器,函数就好比其零部件。l可将这些“零部件”单独设计、调试、测试好,用时拿出来装配,再总体调试。l这些“零部件”可以是自己设计制造/别人设计制造/现在的标准产品函数机制的优点 使程序变得更简短而清晰 有利于程序维护 可以提高程序开发的效率

7、 提高了代码的重用性 函数类型 库函数:由语言系统提供;用户无须定义,也不必在程序中作类型说明;只需在程序前包含有该函数定义的头文件; 自定义函数:用户在程序中根据需要而编写的函数;void main() float x=2,y; y=sqrt(x); printf(“ny=%.3f”, y);必须加上必须加上math.h这个头文件这个头文件#include 函数的使用 Step1. 函数的声明(为调用做准备)声明(为调用做准备) Step2. 函数的定义定义 Step3. 函数的调用调用函数使用是通过调用完成的函数的定义函数定义函数类型 函数名(形参类型说明表)说明部分语句部分现代风格现代风

8、格: :合法标识符函数返回函数返回值类型值类型缺省缺省int型型函数体 有参函数(现代风格)有参函数(现代风格) int max(int x,int y) int z; z=xy?x:y; return(z); 有参函数(现代风格)有参函数(现代风格) int max(int x, y) int z; z=xy?x:y; return(z); 空函数空函数 dummy( ) 函数体为空无参函数无参函数 void printstar( ) printf(“*n”); 或或void printstar(void ) printf(“*n”); 形式参数表形式参数表: :是用逗号分开的一组变量,用来

9、接是用逗号分开的一组变量,用来接收调用时传入的数据。收调用时传入的数据。函数类型 函数名(形参表)形参类型说明说明部分语句部分传统风格传统风格: : int max(x,y) int x,y; int z; z=xy?x:y; return(z); 函数定义函数定义 函数名:需是合法标识符 函数类型:函数返回值类型 如无返回值,则定义为void 缺省的返回值为int类型 形参表:被调用函数接受调用数据的主要 途径,定义时分别给出类型,并用逗号隔开。形参表可以为空,但是圆括号()不能省略函数定义 函数体可以为空,称为空函数 例如 void empty() 函数定义 return语句的格式有三种

10、1、return (expression); 2、return expression; 3、return; 如果函数体中无return语句,则执行到函数末尾时自动返回到调用函数 函数的返回值最多只有一个,可通过return语句返回主调函数函数定义 1、函数类型为void的可以无return语句也可以用return; (但无返回值) 2、其他类型等需要用return语句 3、return语句的功能使程序控制从被调用函数返回到主调函数中,同时把返回值带回给主调函数函数定义void displayDiscount()float price, discount;printf(请输入价格);scanf(

11、%f, &price);discount = 0.75 * price;printf(折扣额为 %f, discount);double max(double x, double y) double m; m=xy?x:y; return m;该函数名为displayDiscount,无参数,使用void说明无返回值,函数体内的语句用于根据产品的价格求折扣后的价格。该函数名为max,它有两个double类型的参数,返回值为double类型。在函数体内有三条语句实现了求两个数中较大的数,并将它返回。函数定义 练习:定义一个函数,参数为两个int类型变量,a,b;函数返回值为a,b内的所有

12、自然数累加和int sum(int a, int b) int s = 0; int i = a; while (iy?x:y: return(z); 实参实参形参形参c=max(a, b); (main函数函数)int max(int x,int y) (max函数函数) int z; z=xy?x:y: return(z); z函数参数说明说明实参和形参数据传递是实参和形参数据传递是“值传递值传递”,即,即单向传递单向传递实参可以是常量、变量或表达式,但必须是实参可以是常量、变量或表达式,但必须是确定确定的值的值a=5;b=2;c=max(3, a+b);形参必须指定类型,形参与形参必须指

13、定类型,形参与实参类型一致,个数相同实参类型一致,个数相同若形参与实参类型不一致,自动将实参按形参类型若形参与实参类型不一致,自动将实参按形参类型转换转换函数调用时转换函数调用时转换c=max(3, 6.8);函数参数abc xy 353592534运行结果:运行结果:3,5,34void main() int a=3,b=5,c; c = n2(a,b); printf(%d,%d,%d,a,b,c);int n2(int x,int y) x=x*x; y=y*y; return(x+y);函数参数 函数相互调用的基本方式:函数相互调用的基本方式:1、函数没有返回值、函数没有返回值使用函数

14、调用语句:例如,使用函数调用语句:例如,printstar();2、函数有返回值、函数有返回值A、赋值,例如,、赋值,例如,c=2*max(a,b);B、函数作为参数、函数作为参数 例例1:printf(%d,max(a,b);例例2:m=max(c,max(a,b);函数调用总结函数正确调用的基本条件 在一个函数中调用另一个函数需具备的条件:在一个函数中调用另一个函数需具备的条件:被调用函数必须是被调用函数必须是已经存在的函数已经存在的函数库函数库函数:在程序开头将定义该库函:在程序开头将定义该库函数的头文件包含数的头文件包含#include*.h自定义函数自定义函数:1、自定义函数在被调函

15、数之前、自定义函数在被调函数之前2、自定义函数在被调函数之后、自定义函数在被调函数之后 需要需要声明声明函数正确调用自定义函数自定义函数在被调函数在被调函数之前之前正确!函数的正确调用自定义函数自定义函数在被调函数在被调函数之后之后出错!对被调用函数的声明和函数原型对被调用函数的声明和函数原型声明的作用声明的作用:告诉编译系统函数名、参数个数及类型,以:告诉编译系统函数名、参数个数及类型,以便检查。便检查。要在主调函数中对被调函数作要在主调函数中对被调函数作声明声明,是由,是由函数原型函数原型来完成来完成的。的。自定义函数在被调函数之后,自定义函数在被调函数之后,需要进行函数的声明!需要进行函

16、数的声明!函数的正确调用函数原型的一般形式:函数原型的一般形式: 函数类型函数类型 函数名(参数类型函数名(参数类型1 参数名参数名1, 参数类型参数类型2 参数名参数名2,);或或函数类型函数类型 函数名(参数类型函数名(参数类型1, 参数类型参数类型2,);float add(float x,float y);main() float a,b,c; scanf(%f,%f,&a,&b); c=add(a,b); printf(%f,c);float add(float x,float y)return(x+y);对函数对函数addadd的声明也可以写成:的声明也可以写成:f

17、loat add(float,float)float add(float,float); ;函数的正确调用函数的正确调用函数原型的说明:函数原型的说明: 被调函数定义在主调函数定义之前,不用作函数声明被调函数定义在主调函数定义之前,不用作函数声明 函数声明在所有函数定义之前,则在主调函数中不必函数声明在所有函数定义之前,则在主调函数中不必对所调用的函数作声明对所调用的函数作声明 float add(float x,float y) return(x+y);void main() float a,b,c; scanf(%f,%f,&a,&b); c=add(a,b); print

18、f(%f,c);float add(float x,float y);void main() float a,b,c; scanf(%f,%f,&a,&b); c=add(a,b); printf(%f,c);float add(float x,float y) return(x+y);函数的正确调用问题描述:根据用户的选择求不同形状的面积。函数调用示例#includevoid AreaOfRect();void AreaOfTriangle();void AreaOfRound();void main() int select; do printf( 0、退出n 1、长方形n

19、 2、三角形n 3、圆形n);printf(请选择功能:);scanf(%d,&select);if(select = 0) break;switch(select) case 1 : AreaOfRect(); break; /长方形 case 2 : AreaOfTriangle(); break; /三角形 case 3 : AreaOfRound(); break; /圆形 default : printf(输入有误,请在 04 之间选择。n); while(1);void AreaOfRect() int x,y; printf(请输入长方形的长:); scanf(%d,&a

20、mp;x); printf(请输入长方形的宽:); scanf(%d,&y); printf(面积为:%dn,(x * y); void AreaOfTriangle() int x,y; printf(请输入三角形的底:); scanf(%d,&x); printf(请输入三角形的高:); scanf(%d,&y); printf(面积为:%dn,(x * y)/2); void AreaOfRound() int r; printf(请输入圆形的半径:); scanf(%d,&r); printf(面积为:%dn,3.14*r*r); 函数原型通过通过函数调

21、用函数调用使使主调函数主调函数得到一个得到一个确定确定的值,这个值就是函的值,这个值就是函数的返回值。数的返回值。函数的返回值是通过函数中的函数的返回值是通过函数中的return语句实现的语句实现的return语句的三种形式:语句的三种形式:return(表达式表达式); return 表达式表达式;return; 比较两个数大小比较两个数大小int max(int x,int y) int z; z=xy?x:y: return(z); void main() int a,b,c; scanf(%d,%d,&a,&b); c=max(a,b); printf(Max is %

22、d,c);return(xy?x:y);函数返回值说明:说明:n 如果需要返回值,则有如果需要返回值,则有return语句;如果主调函数语句;如果主调函数不不需需要返回值,则不用要返回值,则不用return,例如,例如void main( )n 函数中可以有多个函数中可以有多个return,判断是哪个,判断是哪个return退出函数退出函数int max(int x,int y) if (xy) return x; else return y; void main() int a; a=m(3, 5); printf(a%d,a);运行结果:a5函数返回值函数返回值n函数值的类型函数值的类型一

23、般应与一般应与return语句中语句中表达式值的类型表达式值的类型一致一致,如若不一致,在如若不一致,在函数调用时函数调用时自动转换成函数值的类型自动转换成函数值的类型int max(float,float);void main() float a,b; int c; scanf(%f,%f,&a,&b); c=max(a,b); printf(Max is %d,c); int max(float x,int y) float z; z=xy?x:y: return(z); 输入:输入:2.5,3.8运行结果:运行结果: Max is 3函数值的类型函数值的类型决定决定ret

24、urn回去的类型回去的类型n 如果函数中没有如果函数中没有return语句,则返回值是一个无意义的值语句,则返回值是一个无意义的值 如果希望函数没有返回值,则在函数名前加上如果希望函数没有返回值,则在函数名前加上voidvoid printstar() printf(*); main() int a; a=printstar(); printf(%d,a);编译出错编译出错良好的程序设计习惯良好的程序设计习惯为了使程序具有良好的为了使程序具有良好的可读性并减少出错,凡不可读性并减少出错,凡不要求返回值的函数都应定要求返回值的函数都应定义为义为void类型;类型;即使函数类型为即使函数类型为in

25、t型,型,也不要缺省不写也不要缺省不写函数返回值n return只能返回一个变量值。如果想返回多只能返回一个变量值。如果想返回多个变量,怎么办?个变量,怎么办?函数返回值讲指针时候再给大家详细介绍函数调用库函数的调用库函数的调用u输入输出库函数uMath中的库函数u字符串库函数u函数调用的其他形式u值调用u嵌套调用u递归调用函数调用 前面介绍的是函数之间的相互调用 最典型的是传值调用 即:数据从实参 单向传递 到形参值传递实参单向传递到形参函数的值调用 函数之间允许相互调用,也允许嵌套调用 函数还可以自己调用自己,称为递归调用#includevoid main():set_discount()

26、;displayDiscount();:float set_discount() : :float displayDiscount() : :函数调用 void reverse() : :#includevoid main():palindrome();:void palindrome() : reverse(); :函数嵌套调用 函数函数A调用函数调用函数B,函数,函数B调用函数调用函数C,一层层嵌套,一层层嵌套计算计算a,b中自然数的阶乘之和中自然数的阶乘之和SSS/* 此函数用于计算 a 的阶乘 */int factorial(int a) if (a = 1) return 1; el

27、se a = a * factorial(a-1); return a; 函数递归调用 在一个函数体内调用自身称为函数的递归调用 Hanoi(汉诺)塔问题。古代有一个梵塔,塔内有3个座A、B、C,开始时座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个老和尚想把这64个盘子从座移到座,但规定每次只允许移动一个盘,且在移动过程中在3个座上都始终保持大盘在下,小盘在上。在移动过程中可以利用B座。要求编程序输出移动一盘子的步骤。函数递归调用 ABCABC将将3个盘子从个盘子从A移到移到C的全过程的全过程将将2个盘子从个盘子从A移到移到BABC将将3个盘子从个盘子从A移到移到C的全过程的全过程

28、将将2个盘子从个盘子从A移到移到BABC将将3个盘子从个盘子从A移到移到C的全过程的全过程将将1个盘子从个盘子从A移到移到CABC将将3个盘子从个盘子从A移到移到C的全过程的全过程将将1个盘子从个盘子从A移到移到CABC将将3个盘子从个盘子从A移到移到C的全过程的全过程将将2个盘子从个盘子从B移到移到CABC将将3个盘子从个盘子从A移到移到C的全过程的全过程将将2个盘子从个盘子从B移到移到CABC将将2个盘子从个盘子从A移到移到B的过程的过程将将1个盘子从个盘子从A移到移到CABC将将2个盘子从个盘子从A移到移到B的过程的过程将将1个盘子从个盘子从A移到移到CABC将将2个盘子从个盘子从A移到

29、移到B的过程的过程将将1个盘子从个盘子从A移到移到BABC将将2个盘子从个盘子从A移到移到B的过程的过程将将1个盘子从个盘子从A移到移到BABC将将2个盘子从个盘子从A移到移到B的过程的过程将将1个盘子从个盘子从C移到移到BABC将将2个盘子从个盘子从A移到移到B的过程的过程将将1个盘子从个盘子从C移到移到BABC将将2个盘子从个盘子从B移到移到C的过程的过程ABC将将2个盘子从个盘子从B移到移到C的过程的过程ABC将将2个盘子从个盘子从B移到移到C的过程的过程ABC将将2个盘子从个盘子从B移到移到C的过程的过程 由上面的分析可知:将n个盘子从A座移到C座可以分解为以下3个步骤:(1) 将A上

30、n-1个盘借助C座先移到B座上(2) 把A座上剩下的一个盘移到C座上(3) 将n-1个盘从B座借助于座移到C座上 把上面3个步骤分成两类操作:(1) 将n-1个盘从一个座移到另一个座上(n1)。(2) 将1个盘子从一个座上移到另一座上. 编写程序 用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代入#include void h

31、anoi(int n,char one, char two, char three);void move(char x,char y); int main()int m; printf(“the number of diskes:); scanf(%d,&m); printf(move %d diskes:n,m); hanoi(m,A,B,C);void hanoi(int n,char one,char two, char three) if(n=1) move(one,three); else hanoi(n-1,one,three,two); move(one,three);

32、hanoi(n-1,two,one,three); void move(char x,char y) printf(%c-%cn,x,y); 可以用数组名作函数参数,此时形参应当用数组名可以用数组名作函数参数,此时形参应当用数组名或用指针变量或用指针变量 。数组名和指针变量都当作指针来用例例 有一个一维数组有一个一维数组score,内放,内放10个学个学生成绩,求平均成绩。生成绩,求平均成绩。#include float average(float array10); /* 函数声明函数声明 */void main()() float score10 , aver; int ; printf(

33、input scores:n);); for(i=0; i10; i+) scanf(%f,score);); printf(n);); averaverage( score );); printf ( average score is 5.2fn, aver););float average (float array10) int ; float aver,sum=0; for (i=0;i10;i+) sum += arrayi;aver = sum/10;return(aver););运行情况如下:运行情况如下:input 10 scores: 100 56 78 98.5 76 87

34、99 67.5 75 97 average score is 83.40 形参数组不定义长度形参数组不定义长度形参数组不定义长度。形参数组名当作指针来用运行结果如下:运行结果如下:the average of class A is 80.40The average of class is 78.20可以用数组名作函数参数,此时形参应当用数组名可以用数组名作函数参数,此时形参应当用数组名或用指针变量或用指针变量 。数组名和指针变量都当作指针来用运行结果如下:运行结果如下:Max value is 34变量的作用域变量的作用域作用域是某些事物起作用或有效的区域。限于陆地限于海洋限于空中 程序中变量

35、也有不同的使用范围,称为变量的作用域。变量的作用域决定变量的可访问性void displayDiscount() float discount; . . . . . . . . .局部变量:不能在函数外使用float discount;void main() . . . . . .void displayDiscount() . . . . . .全局变量:可以在整个程序中使用 局部变量局部变量-内部变量内部变量定义:在定义:在函数内定义函数内定义,只在本函数内有效只在本函数内有效说明:说明: mainmain中定义的变量只在中定义的变量只在mainmain中有效中有效 不同函数中同名变量,占

36、不同内存单元不同函数中同名变量,占不同内存单元 形参属于局部变量形参属于局部变量 可定义在复合语句中有效的变量可定义在复合语句中有效的变量float f1(int a) int b,c; .char f2(int x,int y) int i,j; main() int m,n; .a,b,c有效x,y,i,j有效m,n有效不同函数中同名变量void main() int a,b; a=3; b=4; printf(main:a=%d,b=%dn,a,b); sub(); printf(main:a=%d,b=%dn,a,b);void sub() int a,b; a=6; b=7; pri

37、ntf(sub:a=%d,b=%dn,a,b);复合语句中变量#define N 5void main() int i; int aN=1,2,3,4,5; for(i=0;iN/2;i+) int temp;temp=ai;ai=aN-i-1;aN-i-1=temp; for(i=0;ib?a:b; return(c);void main() int a=8; printf(max=%d,max(a,b); 全局变量与局部变量运行结果:max=8局部变量和全局变量局部变量和全局变量变量的存储类型 存储类别存储类别: : 规定了变量在计算机内部的存放位置规定了变量在计算机内部的存放位置决定变量

38、的决定变量的“寿寿命命”(何时(何时“生生”,何时,何时“灭灭”) 一个完整的变量说明格式如下:一个完整的变量说明格式如下: 存储类别存储类别 数据类型数据类型 变量名变量名 如如 static int x , y ;static int x , y ;C程序的存储类别有:程序的存储类别有: register型型(寄存器型)(寄存器型) auto型型(自动变量型)(自动变量型) static型型(静态变量型)(静态变量型) extern型型(外部变量型)(外部变量型)C程序的变量存储位置变量的生存期变量的生存期 静态存储区中的变量:静态存储区中的变量:与程序与程序“共存亡共存亡” 动态存储区中的变量:动态存储区中的变量:与函数与函数“共存亡共存亡” 寄存器中的变量:寄存器中的变量:同动态存储区同动态存储区C程序的变量存储类别变量的生存期变量的生存期 静态存储区中的变量静态存储区中的变量 与程序与程序“共存亡共存亡” 动态存储区中的变量动态存储区中的变量 与函数与函数“共存亡共存亡” 寄存器中的变量寄存器中的变量 同动态存储区同动态存储区 register型(寄存器型)型(寄存器型)变量值存放在运算器的寄存器中存取速度快,一般只允许23个,且限于char型和int型,通常用于循环变量 auto型

温馨提示

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

评论

0/150

提交评论