1 / 94

第八章 函数

第八章 函数. 学习目标. 掌握函数的定义和调用 掌握实参和形参的关系 掌握内部变量和外部变量的概念 掌握动态变量和静态变量的概念. 结构化程序设计. 结构化程序设计. 什么是结构化程序设计? 自上而下逐步细化的模块化程序设计方法 结构化程序设计的好处是什么? 复杂问题简单化 便于多人协作完成一个大的任务 提高程序可维护性、可读性 模块复用 C 语言中如何实现结构化程序设计? 模块化在 C 语言中用函数实现. 函数基础. 问题提出. 我们在完成一项工作的时候往往需要由几个人,几个部门甚至几个单位共同来完成。

ginny
Télécharger la présentation

第八章 函数

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第八章函数

  2. 学习目标 • 掌握函数的定义和调用 • 掌握实参和形参的关系 • 掌握内部变量和外部变量的概念 • 掌握动态变量和静态变量的概念

  3. 结构化程序设计

  4. 结构化程序设计 • 什么是结构化程序设计? 自上而下逐步细化的模块化程序设计方法 • 结构化程序设计的好处是什么? 复杂问题简单化 便于多人协作完成一个大的任务 提高程序可维护性、可读性 模块复用 • C语言中如何实现结构化程序设计? 模块化在C语言中用函数实现

  5. 函数基础

  6. 问题提出 • 我们在完成一项工作的时候往往需要由几个人,几个部门甚至几个单位共同来完成。 • 编写一个应用程序也是这样,可以将整个程序分解若干个程序模块,每个程序模块完成一个特定的功能,每个人负责一个或者几个程序模块,分别编写完成。 • c程序库已经提供了一些常用的函数,但是这远远不够,我们需要根据实际编程的要求自定义一些函数,通过自定义函数实现所要求的程序模块功能。

  7. 函数实例 #include <stdio.h> #include <math.h> main() //主函数 { int iNo,b; printf(“input a number:\n”);//输出函数 scanf(“%d”,&iNo); //输入函数 b=sqrt(iNo); //求平方根函数 printf(“%d”,b); //输出函数 }

  8. 函数实例 /*从键盘输入3个数,求和并输出。*/ #include <math.h> #include <stdio.h> int myAdd(int x,int y,int z) { int s; s=x+y+z; return s; } main() { int iNo1,iNo2,iNo3,sum; printf("input 3 numbers:\n");//输出函数 scanf("%d%d%d",&iNo1,&iNo2,&iNo3); //输入函数 sum=myAdd(iNo1,iNo2,iNo3); //用户自定义函数 printf("sum=%d",sum); //输出函数 }

  9. 什么是函数? 函数: 一段函数就是一段实现一定功能的代码,就像一台具有某种功能机器。 因此函数的调用就类似启动一台机器来完成某个任务。 C语言中,函数是实现模块化的工具。

  10. 问题提出:使用函数解决 输入若干个学生的学号、某门课程的平时成绩和期末成绩,计算出总评成绩。其中, 总评成绩 = 50%*平时成绩+50%*期末成绩 最后,从键盘输入一个学生的学号,查询该生的平时成绩、期末成绩和总评成绩。

  11. 问题分析:函数解题思路 • 定义若干具有不同功能的函数,在main函数中分别调用它们,用以解决这个问题。如: • main() • { • /*定义必要的变量*/ • inputScore(); /*输入学生学号及成绩信息* / • computeTotalScore();/*计算每个学生的总成绩*/ • searchByNo(); /*按学号查找某个学生的信息*/ • printSearchInfo();/*输出查找到的学生信息*/ • } main函数只负责解决问题的流程;具体子问题的实现交给不同的函数去处理。

  12. 函数体 函数的定义 除了系统提供的函数外,我们都需要对函数进行定义。 函数定义的通用形式为: 返回值数据类型 函数名称([参数数据类型 参数1 ] ,[ 参数数据类型 参数2, …]) { … } 函数首部

  13. 函数定义案例1 无参数无返回值的函数 如:定义printStar函数,用以在屏幕上输出5个*符号。 void printStar( ) { int star; for(star=1; star<=5; star++) printf("*"); printf("\n") ; } 函数无返回值时使用的数据类型

  14. 函数的调用 • 无参的调用形式: • 函数名();

  15. 无参数无返回值的函数的调用 #include <stdio.h> main( ) { printStar( );//函数调用 } void printStar( ) { int star; for(star=1; star<=5; star++) printf("*"); printf("\n") ; }

  16. 自定义函数的声明 在程序的开头加上对应函数的声明,就不会出现函数未 定义(或重复定义)的错误。 函数声明的形式: 返回值类型 函数名称([参数类型 参数1, …]) ; 其中前面的与函数定义时的首部完全一样,但末尾 必须加“;”。 如对printStar函数的声明为: void printStar( );

  17. 无参数无返回值的函数的声明 #include <stdio.h> printStar( ); /*函数声明*/ main( ) { printStar( ); /*函数调用*/ } void printStar( ) /*函数定义(首部)*/ { int star; for(star=1; star<=5; star++) printf("*"); printf("\n") ; }

  18. 问题提出 • 过年回家,车票难买,到处托人。 • 假如你先把车票钱给帮你买车票的朋友, 那么返回给你的应该是一张车票(当然要顺利的话)。 • 同理,在C语言中,函数的调用有时候也是有返回值的,那么如何理解?

  19. 问题分析 • 对应到函数上,你的朋友就是函数,车票钱是函数输入,车票就是函数的返回值,而你就是调用函数的主程序。

  20. 函数的返回值 • 函数的返回值 • 返回语句 • 形式: return(表达式); • 或 return 表达式; • 或 return; • 功能:使程序控制从被调用函数返回到调用函数中,同时把返值带给调用函数

  21. 函数定义案例2 无参数有返回值的函数 如定义函数sum_100,用以求1+2+3+…+100的和,并将结果返回给调用它的函数。 int sum_100( ) { int s=0, i; for(i=1; i<=100; i++) s=s+i; return s;/*用return返回一个值给主调函数* / }

  22. 无参数有返回值的函数案例 #include <stdio.h> int sum_100( ); /*函数声明*/ main( ) { int s1; s1 = sum_100( ); /*函数调用*/ printf("和值为:%d\n", s1); } int sum_100( ) /*函数定义(首部)*/ { int s=0, i; for(i=1; i<=100; i++) s=s+i; return s; /*返回值给主调函数*/ }

  23. 模仿练习 • 无参无返回值函数编写: 1、自定义函数myPrint1(),在屏幕上输出如下图形(每行10个$符号),并在主函数中调用myPrint1()函数。 $$$$$$$$$$ $$$$$$$$$$ $$$$$$$$$$

  24. 模仿练习 • 无参无返回值函数编写: 2、自定义函数myPrint2(),在屏幕上输出如下图形,并在主函数中调用myPrint2()函数。 @ @@@ @@@@@ @@@@@@@ @@@@@@@@@

  25. 模仿练习 • 无参有返回值函数编写: 3、自定义函数myFac(),计算10!,将计算结果返回给调用者。然后在主函数中调用myFac()函数,输出该结果。 4、自定义函数myMax(),实现功能:从键盘输入3个数,求最大数并在主函数中调用myMax()函数,输出该结果。

  26. 讨论 1、为什么使用函数? 2、如何理解函数调用与函数定义的不同? 3、空函数在程序结构设计中有什么作用?

  27. 学以致用 将自己的“学生成绩管理系统”(循环菜单)以模块化的形式进行处理,具体实施方案: • 主菜单的显示和选择部分可定义函数menu_select()来调用, • “编辑子菜单”可定义editmenu()来调用, • “查找”可定义serachmenu()来调用。

  28. 有参函数

  29. 函数定义案例3 有参数无返回值的函数 如定义printStar_n()函数,用以在屏幕的一行上输出n个*号。其中n的值是由调用该函数的函数传递过来的。 void printStar_n( int n) { int star; for(star=1; star<=n; star++) printf("*"); printf("\n"); } 函数参数(称为形参)

  30. 函数调用 有参函数的调用形式: 函数名(实参); 实参与形参: • 个数相等 • 类型一致 • 按顺序一一对应

  31. 调用时传递的参数(称为实参) 函数参数(称为形参) 有参数无返回值的函数调用 #include <stdio.h> void printStar2(int n); //函数声明 main( ) { int starNum; scanf("%d", &starNum); printStar_n(starNum); //函数调用 } void printStar_n( int n) //函数定义(首部) { int star; for(star=1; star<=n; star++) printf("*"); printf("\n"); }

  32. 函数参数(称为形参) 函数定义案例4 有参数有返回值的函数 如定义函数sum_n(),用以求1+2+3+…+n的和,并将结果返回给调用它的函数。 int sum_n( int n ) { int s=0, i; for(i=1; i<=n; i++) s=s+i; return s; /*通过return返回一个值*/ }

  33. 有参数有返回值的函数调用 #include <stdio.h> int sum_n( int n ); /*函数声明*/ main( ) { int s1, n; scanf("%d", &n); s1 = sum_n(n );/*函数调用*/ printf("和值为:%d\n", s1); } int sum_n( n ) /*函数定义 (首部) */ { int s=0, i; for(i=1; i<=n; i++) s=s+i; return s; /*返回一个值给主调函数*/ }

  34. 函数的调用 1、语句调用方式 2、函数表达式 3、函数参数

  35. 函数的调用 调用方式 • 语句调用: 例 printmsg(); printf(“打印成功!\n”); • 函数表达式调用: 例 result=aver(totalscore, stuno); • 函数参数调用: 例 printf(“%f”,aver(totalscore, stuno));

  36. 模拟练习 • 有参无返回值函数编写: • 1、自定义函数myprint_n(),在屏幕的一行上输出n个$符号。在主函数中调用myprint_n()函数,输出如下图形(每行上的符号个数由调用它的函数传递过来) 。 • 函数首部为:void myprint_n( int n) • $$$$$(5个$) • $$$$$$$$$$(10个) • $$$$$$$$$$$$$$$(15个) • $$$$$$$$$$$$$$$$$$$$(20个) • 2、修改以上程序,实现以下功能:打印个数由用户输入决定,支持用户循环输入,当用户输入0时结束程序。

  37. 讨论 1、函数的功能应该尽量保持相对独立还是依 赖函数外的数据为好 ? 2、怎样使一个函数具有更大的通用性? 3、函数参数的值传递有哪些特点?

  38. 扩展练习 将“控制流程”阶段完成的“小型计算器”功能改写为函数,并在主函数中调用,注意参数的类型定义及传参过程。

  39. 函数的值传递

  40. 函数的值传递方式 #include <stdio.h> void main() { void swap(int a,int b); /*swap函数的声明*/ int x=7,y=11; printf("x=%d,\ty=%d\n",x,y); printf("swapped:\n"); swap(x,y); /*调用swap函数*/ printf("x=%d,\ty=%d\n",x,y); } void swap(int a,int b) /*定义swap函数*/ { int temp; temp=a; a=b; b=temp; } 输出结果:x=7, y=11 swapped: x=7, y=11

  41. 结论 值传递方式 • 方式: • 函数调用时,为形参分配单元,并将实参的值复制到形参中; • 调用结束,形参单元被释放,实参单元仍保留并维持原值 • 特点: • 形参与实参占用不同的内存单元 • 单向传递

  42. 结论 • 函数参数的传递方式还有另一种---地址传递方式 • 其传递的参数为地址而不是值,具体内容将在数组章节中学习.

  43. 变量的储存类别

  44. 问题提出 #include <stdio.h> void prt(); main() { int x; for(x=1; x<=5; x++) prt(); } void prt() { static int y=0; y++; printf("%d", y); } 输出结果:12345 去掉static后的 结果为多少?

  45. 问题分析 • 动态存储变量和静态存储变量 • 动态变量:用auto关键字表示 • 如auto int p, f; //p,f为两个动态变量 • 在C中,默认的变量定义就是定义为动态变量 • 即上述的p,f变量定义与 int p, f; 是完全等价的。 • 静态变量:在程序生存期内一直有效。 • 注意,如果静态变量出现在函数中,不会因为函数的调用结束而丢失这个变量的值

  46. 变量的生存期 内部变量与外部变量的作用区域是不一样的。 int a,b,c; //外部变量定义 main() { int x, y; //内部变量 float f; //内部变量 //其他语句… } int sum(int n) { int s=0, i; //内部变量 //语句 } x, y, f的 有效区域 a, b, c的 有效区域 s,i的 有效区域

  47. 小结 1、变量的存储类型 计算机的存储器分为内存和外存。还有一个小小的临时存储器称为寄存器,用以存储一些反复被加工的数据。 C语言允许程序员区分是在主存还是在寄存器中开辟变量的存储空间。 2、变量的生存期 (1)在编译时分配存储单元。这种变量的生存期为程序执行的整个过程,在该过程中占有固定的存储空间,称为永久存储。 (2)只在程序执行的某一段时间内存在。比如在函数的执行过程中存在。这种存储方式称为动态存储。

  48. 3、变量的可用域 变量的可用域也分为全局可用和局部可用。 C语言中,用“存储属性”来表示以上三个方面的属 性,如表所示。 小结

  49. 模仿练习 1、写出以下程序的运行结果: intfun(int a) /*a为形参,自动型局部变量*/ { auto int b=0; /*b是自动型局部变量*/ static int c=3; /*c是静态型局部变量,初始化仅进行一次*/ b+=1; c=c+1; return a+b+c; } main() { int a=2,i; /*a和i都是自动型局部变量*/ for(i=0;i<3;i++) printf("%d\t",fun(a)); }

  50. 模仿练习 2、写出以下程序的运行结果: int sum(int n); //函数声明 int a=4,b=5,c=6; //外部变量定义 main() { int x=1, y=2; float f=3.0; x=sum(10); printf("x=%d,y=%d,f=%f\n", x, y, f); printf("a=%d,b=%d,c=%d\n", a, b, c); //printf("s=%d, i=%d\n", s, i); } int sum(int n) { int s=0, i; for(i=1; i<=n; i++) s = s+i; printf("s=%d, i=%d\n", s, i); printf("a=%d,b=%d,c=%d\n", a, b, c); //printf("x=%d,y=%d,f=%f\n", x, y, f); return s; }

More Related