c语言大学实用教程函数.pptx
内容提要函数定义、函数调用、函数原型、函数返回值难点:函数的参数传递与返回值 全局变量、自动变量、静态变量、寄存器变量难点:变量的作用域与存储类型 结构设计与模块化 代码风格问题MoeCurlyLarry第1页/共79页程序设计的艺术程序设计方式A.诸葛亮型的主函数1986年IBM在OS/360的研究结果:大多数有错误的函数都大于500行B.功能单一,规模较小的若干个函数各司其职1991年对148,000行代码的研究表明:小于143行的函数比更长的函数更容易维护第2页/共79页程序设计的艺术三国演义中有这样一段描写:懿问曰:“孔明寝食及事之烦简若何?”使者曰:“丞相夙兴夜寐,罚二十以上皆亲览焉。所啖之食,日不过数升。”懿顾谓诸将曰:“孔明食少事烦,其能久乎?”此话音落不久,诸葛亮果然病故于五丈原。“事无巨细”,“事必躬亲”管理学的观点是极其排斥这种做法的,认为工作必须分工,各司其职其中的思想,在程序设计里也适用 第3页/共79页程序设计的艺术结构化程序设计有两大最高级的艺术算法设计艺术结构设计艺术C语言为程序的结构提供了两样武器函数和模块函数(function)是结构设计的最基本单位“一个程序应该是轻灵自由的,它的子过程就象串在一根线上的珍珠。”Geoffrey James的编程之道 第4页/共79页数学函数(1)(1)自变量自变量因变量因变量函数名函数名第5页/共79页数学函数(2)(2)一个自变量,一个因变量一个自变量,一个因变量两个两个自变量,一个因变量自变量,一个因变量第6页/共79页数学函数(3)(3)自变量自变量因变量因变量第7页/共79页数学函数(4)(4)一个变量一个变量二个变量二个变量N个变量个变量一个变量一个变量二个变量二个变量N个变量个变量自变量与自变量与因变量的因变量的关系关系第8页/共79页数学函数(5)(5)集合A关系集合B第9页/共79页程序设计中的函数程序设计中的函数不局限于计算计算类,如打印阶乘表的程序判断推理类,如排序、查找第10页/共79页用函数解决问题的要点分而治之函数把较大的任务分解成若干个较小的任务,并提炼出公用任务复用程序员可以在其他函数的基础上构造程序,而不需要从头做起信息隐藏设计得当的函数可以把具体操作细节对程序中不需要知道它们的那些部分隐藏掉,从而使整个程序结构清楚MoeCurlyLarry第11页/共79页C中的函数(Function)说明:L一个源程序文件由一个或多个函数组成。LC程序的执行从main函数开始,调用其他函数后流程回到main函数,在main函数中结束整个程序运行。L所有函数都是平行的,即函数定义时是互相独立的,一个函数并不从属于另一个函数。第12页/共79页例2.1:一个简单的C程序例子#include/*函数功能:计算两个整数相加之和 入口参数:整型数据a和b 返回值:整型数a和b之和*/int Add(int a,int b)return(a+b);/*主函数*/main()int x,y,sum=0;printf(Input two integers:);scanf(%d%d,&x,&y);/*输入两个整型数x和y*/sum=Add(x,y);/*调用函数Add计算x和y相加之和*/printf(sum=%dn,sum);/*输出x和y相加之和*/并列的两个函数并列的两个函数并列的两个函数并列的两个函数其中一个是其中一个是其中一个是其中一个是程序的入口程序的入口程序的入口程序的入口程序注释程序注释程序注释程序注释第13页/共79页函数的分类 标准函数,即库函数 用户自定义函数 第14页/共79页函数定义(definition)返回值类型 函数名(类型 参数1,类型 参数2,)函数体return 表达式;如果没有参数,则应该用void注明函数的返回值只有一个如果不需要返回值,则应该用void定义返回值类型返回值类型与return语句配合当函数执行到return语句时,就中止函数的执行,返回到调用它的地方函数内部可以定义只能自己使用的变量,称内部变量。参数表里的变量也是内部变量函数的返回值是通过函数的返回值是通过函数中的函数中的 return 语句获得的。语句获得的。第15页/共79页函数参数函数参数:形参(形式参数):在定义函数时,定义函数名后面括号中的变量名实参(实际参数):在主调函数中调用一个函数,调用函数名后面括号中的参数(或表达式)int Average(int x,int y)int result;result=(x+y)/2;return result;main()int a=12;int b=24;int ave;ave=Average(a,b);printf();数据传递执行顺序实参实参实参实参形参形参形参形参第16页/共79页实参的数量必须与形参相等,对应的类型必须匹配;实参与形参有各自的存储空间,所以形参值的改变不会影响实参;参数的类型没有限制,也可以定义没有参数的函数;第17页/共79页函数调用(call)从实参到形参是单向值传递调用函数时,必须提供所有的参数(且必须是已赋值的)特例,printf和scanf是采用变长变量表定义的函数,所以变量的个数不固定。提供的参数个数、类型、顺序应与定义时相同形式参数形式参数形式参数形式参数实际参数实际参数实际参数实际参数第18页/共79页例5.1a 计算两个整数的平均数/*函数功能:计算平均数 函数入口参数:整型x,存储第一个运算数 整型y,存储第二个运算数 函数返回值:平均数*/int Average(int x,int y)int result;result=(x+y)/2;return result;第19页/共79页例5.1b 使用了Average函数的main()main()int a=12;int b=24;int ave;ave=Average(a,b);printf(Average of%d and%d is%d.n,a,b,ave);int Average(int x,int y)int result;result=(x+y)/2;return result;main()int a=12;int b=24;int ave;ave=Average(a,b);printf();数据传递执行顺序第20页/共79页函数调用(call)有返回值时放到一个数值表达式中如 c=max(a,b);作为另一个函数调用的参数如 c=max(max(a,b),c);printf(%dn,max(a,b);无返回值时函数调用表达式如 display(a,b);返回值返回值返回值返回值 =函数名函数名函数名函数名(实参表列实参表列实参表列实参表列););函数名函数名函数名函数名(实参表列实参表列实参表列实参表列););第21页/共79页函数原型(prototype)返回值类型 函数名(类型 参数1,类型 参数2,);调用一个函数之前,先要对其返回值类型、函数名和参数进行声明(declare)(不声明也能使用,但运行结果可能不稳定)有助于编译器进行类型检查除了末尾分号外,声明的语法格式与函数定义的首部完全一致;第22页/共79页例5.1#include int Average(int x,int y);/*声明Average()函数*/main()int a=12;int b=24;int ave=Average(a,b);printf(Average of%d and%d is%d.n,a,b,ave);/*函数功能:计算平均数 函数入口参数:整型x,存储第一个运算数 整型y,存储第二个运算数 函数返回值:平均数*/int Average(int x,int y)int result;result=(x+y)/2;return result;第23页/共79页例5.1 int Average(int x,int y);/*声明Average()函数*/main()/*主函数*/int ave=Average(a,b);/*调用函数Average*/int Average(int x,int y)/*自定义函数Average*/第24页/共79页例5.1#include/*函数功能:计算平均数 函数入口参数:整型x,存储第一个运算数 整型y,存储第二个运算数 函数返回值:平均数*/int Average(int x,int y)int result;result=(x+y)/2;return result;main()int a=12;int b=24;int ave=Average(a,b);printf(Average of%d and%d is%d.n,a,b,ave);当返回值为整型或者函数定义在函当返回值为整型或者函数定义在函数调用前面时,可以省略原型数调用前面时,可以省略原型第25页/共79页main()a();a 函数函数b();return;b函数函数return;在被调函数中,又调用了函数在被调函数中,又调用了函数-嵌套调用嵌套调用函数的嵌套调用函数的嵌套调用函数的嵌套调用函数的嵌套调用第26页/共79页循序渐进式编程实验4:小学生加法考试题 通过输入两个加数给学通过输入两个加数给学生出一道加法运算题生出一道加法运算题输入答案正确输入答案正确:right错误错误:Not correct!Try again!第27页/共79页只答1次直到做对为止最多给3次机会随机出题连续做10道题统计分数循序渐进式编程实验4:小学生加法考试题 第28页/共79页void Print(int flag)void Print(int flag)if(flag)if(flag)printf(Right!n);printf(Right!n);else else printf(Not correct!n);printf(Not correct!n);实验4:小学生加法考试题/*函数功能:计算两整型数之和,如果与用户输入的答案相同,则返回1,否则返回0 函数参数:整型变量a和b,分别代表被加数和加数 函数返回值:当a加b的结果与用户输入的答案相同时,返回1,否则返回0*/int AddTest(int a,int b)int answer;printf(%d+%d=,a,b);scanf(%d,&answer);if(a+b=answer)return 1;else return 0;只答1次第29页/共79页main()int a,b,answer;printf(Input a,b:);scanf(%d,%d,&a,&b);answer=AddTest(a,b);Print(answer);do while(answer=0);实验4:小学生加法考试题 直到做对为止第30页/共79页main()answer=AddTest(a,b);Print(answer,chance);chance=0;do chance+;while(answer=0&chance 3);实验4:小学生加法考试题 最多给3次机会第31页/共79页 srand(time(NULL);error=0;score=0;for(i=0;i10;i+)a=rand()%10+1;b=rand()%10+1;answer=AddTest(a,b);Print(answer);if(answer=1)score=score+10;else error+;实验4:小学生加法考试题 随机出题连续做10道题统计分数第32页/共79页作业P162,5.7,5.8第33页/共79页软件测试测试通过运行测试用例找出软件中的Bug测试的目的发现更多的Bug测试人员的主要任务站在使用者的角度,通过不断使用和攻击,尽量多的找出Bug如何提高可测试性(tesability)一条语句写一行才容易测试第34页/共79页软件测试 测试只能证明程序有错,不能测试只能证明程序有错,不能测试只能证明程序有错,不能测试只能证明程序有错,不能证明程序无错证明程序无错证明程序无错证明程序无错 E.W.Dijkstra E.W.Dijkstra测试的重要性测试人员水平越高,找到Bug的时间就越早,软件就越容易修复,产品发行就越稳定越大型的软件开发,测试人员占整个软件产品团队的总人数的比重就越大,甚至一半以上成功的测试在于发现迄今为止尚未发现的Bug第35页/共79页软件测试方法的分类从代码和用户使用的角度分类覆盖性测试从代码特性的角度(即内部)出发的测试单元测试,功能测试,提交测试,基本验证测试,回归测试使用测试从用户的角度(即外部)出发的测试配置测试,兼容性测试,性能测试,Alpha和Beta测试,强力测试,文档和帮助文件测试第36页/共79页软件测试方法的分类第2种分类方法白盒测试(结构测试)在完全了解程序的结构和处理过程的情况下,按照程序内部的逻辑测试程序,检验程序中的每条通路是否都能按预定要求正确工作黑盒测试(功能测试)不考虑程序内部的结构和处理过程第37页/共79页软件测试方法的分类第3种分类方法手工测试依靠人力来查找Bug自动测试编写一些测试工具,让他们自动运行来查找Bug优点:快,广泛缺点:只能检查一些最重要的问题,如内存泄漏、死机等,无法发现一般性的日常错误,而且编写测试工具的工作量很大第38页/共79页程序中常见的出错原因编译错误指在编译过程中发现的错误,通常属于语法错误,即编写的语句不符合C语言的语法规则。Undefined symbol xxx 标识符xxx未定义Expression syntax error 表达式语法错误Too few parameter in call 函数调用时的实参少于函数的形参第39页/共79页程序中常见的出错原因运行错误指在程序运行时发生的错误往往是由于语义上的错误造成的,即语句虽然合乎语法,但要求计算机去做不该做或做不到的事情。例如当用0做除数时,运行后将显示“Division by zero”错误提示信息,并立即返回编辑屏幕。查看运行结果时,可在User screen(用户屏幕)上看到给出的错误提示信息。第40页/共79页程序中常见的出错原因逻辑错误程序中有逻辑错时,不影响程序运行并得到运行结果,只是运行结果不正确。比较隐蔽,出错后不易查找。累加求和运算时,累加和变量忘记了赋初值;累乘运算时,累乘变量初值赋值为0;函数声明时的返回值数据类型与实际返回的数据类型不一致,导致自动类型转换数组下标越界(即超出了定义的范围);程序中存在死循环;第41页/共79页调试的基本方法调试的基本方法“粗分细找”定位大致的范围:归纳、推理、二分、排除缩减输入数据设法找到能导致失败的最小输入 采用注释的办法切掉一些代码减少有关的代码区域,调试无误后再将它们打开注释,即采用分而治之的策略将问题局部化 利用调试工具逐条语句跟踪插入打印语句观看屏幕输出结果第42页/共79页43VC+6.0VC+6.0中的调试功能项及快捷键快捷键快捷键快捷键快捷键菜单项菜单项菜单项菜单项功功功功 能能能能Ctrl+F10Ctrl+F10Run to CursorRun to Cursor执行到光标所在的那一行执行到光标所在的那一行执行到光标所在的那一行执行到光标所在的那一行F5F5RunRun执行程序直至断点或程序结束执行程序直至断点或程序结束执行程序直至断点或程序结束执行程序直至断点或程序结束F11F11Step IntoStep Into单步执行,执行当前一行,若当前行有自单步执行,执行当前一行,若当前行有自单步执行,执行当前一行,若当前行有自单步执行,执行当前一行,若当前行有自定义函数,则进入函数内部定义函数,则进入函数内部定义函数,则进入函数内部定义函数,则进入函数内部F10F10Step OverStep Over单步执行,执行当前一行单步执行,执行当前一行单步执行,执行当前一行单步执行,执行当前一行Shift+F11Shift+F11Step OutStep Out执行至本函数结束,回到调用者执行至本函数结束,回到调用者执行至本函数结束,回到调用者执行至本函数结束,回到调用者Shift+F5Shift+F5Stop DebuggingStop Debugging终止运行,回到未运行状态终止运行,回到未运行状态终止运行,回到未运行状态终止运行,回到未运行状态Ctrl+Shift+Ctrl+Shift+F5F5RestartRestart从头开始重新运行程序,直至断点或程序从头开始重新运行程序,直至断点或程序从头开始重新运行程序,直至断点或程序从头开始重新运行程序,直至断点或程序结束结束结束结束第43页/共79页程序调试实例 例5.11#include int Factorial(int x);main()int x;while(1)/*无限循环*/printf(请输入一个正整数 x(若输入-1退出程序):);scanf(%d,&x);if(x=-1)break;/*循环出口*/else printf(The factorial of%d is%d.n,x,Factorial(x);存在一处错误!存在一处错误!存在一处错误!存在一处错误!第44页/共79页程序调试实例 例5.11/*函数功能:计算x的阶乘 函数入口参数:整型x 函数返回值:阶乘运算结果*/int Factorial(int x)int i,result;for(i=1;i=x;i+)result*=i;return result;存在一处错误!存在一处错误!存在一处错误!存在一处错误!第45页/共79页程序调试实例 例5.11/*函数功能:计算x的阶乘 函数入口参数:无符号长整型x 函数返回值:阶乘运算结果*/unsigned long Factorial(unsigned int x)unsigned long i,result=1;for(i=2;i=x;i+)result*=i;return result;第46页/共79页关于代码风格问题缩进(indent)保证代码整洁、层次清晰的主要手段int isprime(int n)int isprime(int n)int k,i;int k,i;k=sqrt(double)n);k=sqrt(double)n);for(i=2;i=k;i+)for(i=2;i=k;i+)if(n%i=0)return 0;if(n%i=0)return 0;return 1;return 1;#include#includemain()main()int i;int i;for(i=2;i100;i+)for(i=2;i100;i+)if(isprime(i)if(isprime(i)printf(%dt,i);printf(%dt,i);第47页/共79页关于代码风格问题良好风格的程序应严格采用梯形层次对应好各层次intint IsPrime(IsPrime(intint n)n)intint k,i;k,i;k=sqrt(k=sqrt(doubledouble)n);)n);forfor(i=2;i=k;i+)(i=2;i=k;i+)ifif(n%i=0)(n%i=0)returnreturn 0;0;returnreturn 1;1;#includeinclude main()main()intint i;i;forfor(i=2;i100;i+)(i=2;i100;i+)ifif(IsPrime(i)(IsPrime(i)printf(%dt,i);printf(%dt,i);第48页/共79页程序版式现在的许多开发环境、编辑软件都支持“自动缩进”根据用户代码的输入,智能判断应该缩进还是反缩进,替用户完成调整缩进的工作VC中有自动整理格式功能只要选取需要的代码,按ALT+F8就能自动整理第49页/共79页命名规则在Linux/Unix平台习惯用function_name 本书采用Windows风格函数名命名用大写字母开头、大小写混排的单词组合而成 FunctionName 变量名形式“名词”或者“形容词+名词”如变量名oldValue与newValue等函数名形式“动词”或者“动词+名词”(动宾词组)如函数名GetMax()等 第50页/共79页对函数接口加以注释说明/*函数功能:实现功能 函数参数:参数1,表示 参数2,表示 函数返回值:*/返回值类型 函数名(参数表)函数体return 表达式;第51页/共79页变量的作用域 指在源程序中定义变量的位置及其能被读写访问的范围分为局部变量(Local Variable)全局变量(Global Variable)第52页/共79页局部变量局部变量在语句块/函数内定义的变量形参也是局部变量特点定义时不会自动初始化,除非程序员指定初值进入语句块时获得内存,仅能由语句块内语句访问,退出语句块时释放内存,不再有效 并列语句块各自定义的同名变量互不干扰 第53页/共79页全局变量全局变量在所有函数之外定义的变量特点在程序中定义它的位置以后都有效在定义点之前或在其他文件中引用,应该进行如下声明:extern 类型名 变量名;从程序运行起即占据内存,程序运行过程中可随时访问,程序退出时释放内存 使函数之间的数据交换更容易,也更高效但是并不推荐使用,尽量少用因为谁都可以改写全局变量,所以很难确定是谁改写了它P140P140:全局变量不指定初始值时程序自动初始化为:全局变量不指定初始值时程序自动初始化为0.0.第54页/共79页例5.7#include int global=1;/*定义全局变量*/void GlobalPlusPlus(void);main()printf(Before GlobalPlusPlus(),it is%dn,global);GlobalPlusPlus();printf(After GlobalPlusPlus(),it is%dn,global);/*函数功能:对全局变量global加1,并打印加1之前与之后的值 函数入口参数:无 函数返回值:无*/void GlobalPlusPlus(void)printf(Before+,it is%dn,global);global+;printf(After+,it is%dn,global);Before GlobalPlusPlus(),it is 1Before GlobalPlusPlus(),it is 1Before+,it is 1Before+,it is 1After+,it is 2After+,it is 2After GlobalPlusPlus(),it is 2After GlobalPlusPlus(),it is 2第55页/共79页例5.7#include void GlobalPlusPlus(void);main()int global=1;printf(Before GlobalPlusPlus(),it is%dn,global);GlobalPlusPlus();printf(After GlobalPlusPlus(),it is%dn,global);/*函数功能:对局部变量global加1,并打印加1之前与之后的值 函数入口参数:无 函数返回值:无*/void GlobalPlusPlus(void)int global=1;printf(Before+,it is%dn,global);global+;printf(After+,it is%dn,global);Before GlobalPlusPlus(),it is 1Before GlobalPlusPlus(),it is 1Before+,it is 1Before+,it is 1After+,it is 2After+,it is 2After GlobalPlusPlus(),it is 1After GlobalPlusPlus(),it is 1第56页/共79页例例 外部变量与局部变量同名外部变量与局部变量同名#include int a=3,b=5;/*a,b为外部变量*/void main()int a=8;/*a为局部变量*/printf(%dn,max(a,b);max(int a,int b)/*a,b为局部变量*/int c;c=ab?a:b;return(c);运行结果为运行结果为 8 第57页/共79页例5.7#include void GlobalPlusPlus(void);int main(void)int global;printf(Before GlobalPlusPlus(),it is%dn,global);GlobalPlusPlus();printf(After GlobalPlusPlus(),it is%dn,global);return 0;/*函数功能:对局部变量global加1,并打印加1之前与之后的值 函数入口参数:无 函数返回值:无*/int global=1;void GlobalPlusPlus(void)printf(Before+,it is%dn,global);global+;printf(After+,it is%dn,global);Before GlobalPlusPlus(),it is 1812Before GlobalPlusPlus(),it is 1812Before+,it is 1Before+,it is 1After+,it is 2After+,it is 2After GlobalPlusPlus(),it is 1812After GlobalPlusPlus(),it is 1812随机值随机值第58页/共79页例5.7#include void GlobalPlusPlus(void);int main(void)extern int global;printf(Before GlobalPlusPlus(),it is%dn,global);GlobalPlusPlus();printf(After GlobalPlusPlus(),it is%dn,global);return 0;/*函数功能:对局部变量global加1,并打印加1之前与之后的值 函数入口参数:无 函数返回值:无*/int global=1;void GlobalPlusPlus(void)printf(Before+,it is%dn,global);global+;printf(After+,it is%dn,global);Before GlobalPlusPlus(),it is 1Before GlobalPlusPlus(),it is 1Before+,it is 1Before+,it is 1After+,it is 2After+,it is 2After GlobalPlusPlus(),it is 2After GlobalPlusPlus(),it is 2第59页/共79页变量的存储类型 指数据在内存中存储的方式即编译器为变量分配内存的方式,它决定变量的生存期动态存储根据需要临时分配存储空间,离开即释放静态存储在程序运行期间分配固定的存储空间不释放程序区程序区静态存储区静态存储区动态存储区动态存储区形参、自动变形参、自动变量、函数调用量、函数调用的现场等的现场等全局变量、全局变量、静态变量静态变量第60页/共79页静态变量(static)一般的内部变量在函数退出后失效,再次进入函数,变量值重新初始化静态变量在变量类型前面用static修饰static int i;变量的值可以保存到下次进入函数,使函数具有记忆功能第62页/共79页例5.8#include void Func(void);main()int i;for(i=0;i10;i+)Func();/*函数功能:打印被调用的次数 函数入口参数:无 函数返回值:无*/void Func(void)int times=1;/*自动变量*/printf(Func()was called%d time(s).n,times+);Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 1 time(s).第63页/共79页例5.8#include void Func(void);main()int i;for(i=0;i10;i+)Func();/*函数功能:打印被调用的次数 函数入口参数:无 函数返回值:无*/void Func(void)static int times=1;/*静态局部变量*/printf(Func()was called%d time(s).n,times+);Func()was called 1 time(s).Func()was called 1 time(s).Func()was called 2 time(s).Func()was called 2 time(s).Func()was called 3 time(s).Func()was called 3 time(s).Func()was called 4 time(s).Func()was called 4 time(s).Func()was called 5 time(s).Func()was called 5 time(s).Func()was called 6 time(s).Func()was called 6 time(s).Func()was called 7 time(s).Func()was called 7 time(s).Func()was called 8 time(s).Func()was called 8 time(s).Func()was called 9 time(s).Func()was called 9 time(s).Func()was called 10 time(s).Func()was called 10 time(s).第64页/共79页静态变量静态变量和全局变量都是静态存储类型自动初始化为0从静态存储区分配,生存期为整个程序运行期间但作用域不同程序区程序区静态存储区静态存储区动态存储区动态存储区形参、自动变形参、自动变量、函数调用量、函数调用的现场等的现场等全局变量、全局变量、静态变量静态变量第65页/共79页模块化程序设计方法什么时候需要模块化?某一功能,如果重复实现3遍以上,即应考虑模块化,将它写成通用函数,并向小组成员发布要尽可能复用其它人的现成模块。第67页/共79页习题5.7计算复用Factorial函数的代码unsigned long Factorial(unsigned int number);main()unsigned int m,k;unsigned long p;printf(Please input m,k:);scanf(%u,%u,&m,&k);p=Factorial(k)/Factorial(m-k);printf(p=%lun,p);第68页/共79页/*函数功能:计算无符号整型数number的阶乘*/unsigned long Factorial(unsigned int number)unsigned long i,result=1;for(i=2;i=number;i+)result*=i;return result;第69页/共79页模块化程序设计方法功能分解自顶向下、逐步求精的过程模块分解的原则保证模块的相对独立性高聚合、低耦合模块的实现细节对外不可见外部:关心做什么内部:关心怎么做设计好模块接口接口是指罗列出一个模块的所有的与外部打交道的变量等 定义好后不要轻易改动在模块开头(文件的开头)进行函数声明第70页/共79页函数设计的原则函数的功能要单一,不要设计多用途的函数 函数的规模要小,尽量控制在50行代码以内1986年IBM在OS/360的研究结果:大多数有错误的函数都大于500行1991年对148,000行代码的研究表明:小于143行的函数比更长的函数更容易维护参数和返回值的规则参数要书写完整,不要省略对函数的入口参数进行有效性检查没有参数和返回值时,用void填充每个函数只有一个入口和一个出口,尽量不使用全局变量尽量少用静态局部变量,以避免使函数具有“记忆”功能第71页/共79页模块和链接 优点:当一个文件的代码被修改后,不必对所有程序重新编译,从而节省了程序的编译时间。使程序更宜于维护,给多个程序员共同编制一个大型项目的代码提供了方便手段。第74页/共79页5.9 递归P154 汉诺塔问题函数自己调用自己例5-12 计算n!第75页/共79页#include long fact(long n);int main(void)int n;long result;printf(Input n:);scanf(%d,&n);result=fact(n);if(result!=0)printf(%d!=%ldn,n,result);/*/函数功能:当n2时递归计算n!的值。当n为0或1时,返回1;当n小于0时,返回0*/long fact(long n)long result;if(n 0)return 0;/*如果n0,打印出错信息*/else if(n=0|n=1)return 1;/*递归终止条件*/else result=n*fact(n-1);/*递归调用*/return result;第76页/共79页这一章我们学习了函数的定义、调用变量的作用域、存储类自动变量(auto)外部变量(extern)静态变量(static)寄存器变量(register)程序调试方法第77页/共79页作业P162,习题5.7第78页/共79页感谢您的观看!第79页/共79页