1 / 56

温故知新

温故知新. 函数. 1 、 C 语言是由 构成的?. 函数. ( 是 C 程序的基本单位?). 2 、一个 C 程序只能由一个函数构成,并且这个函数是 main( ) 。. ×. 编写程序,求 s=s1+s2+s3+s4 的值, 其中 : s1 =1+1/2+1/3+…+1/ 50 s2 =1+1/2+1/3+…+1/ 100 s3 =1+1/2+1/3+…+1/ 150 s4 =1+1/2+1/3+…+1/ 200. #include “stdio.h” main () {

nadine
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. 温故知新 函数 1、C语言是由构成的? 函数 ( 是C程序的基本单位?) 2、一个C程序只能由一个函数构成,并且这个函数是main( ) 。 ×

  2. 编写程序,求s=s1+s2+s3+s4 的值, 其中: s1 =1+1/2+1/3+…+1/50 s2 =1+1/2+1/3+…+1/100 s3 =1+1/2+1/3+…+1/150 s4 =1+1/2+1/3+…+1/200

  3. #include “stdio.h” main() { float s1=0,s2=0,s3=0,s4=0,sum=0; int i; for(i=1;i<=50;i++) s1+=1/(float)i; for(i=1;i<=100;i++) s2+=1/(float)i; for(i=1;i<=150;i++) s3+=1/(float)i; for(i=1;i<=200;i++) s4+=1/(float)i; sum=s1+s2+s3+s4; printf(″sum=%f″,sum); }

  4. 此题目可以首先编一函数,用于求1+1/2+1/3+…+1/n的值,此题目可以首先编一函数,用于求1+1/2+1/3+…+1/n的值, 然后通过函数调用求s的值。 #include “stdio.h” float Fcount(int n) { float s; int i; s=0; for(i=1;i<=n;i++) s+=1/(float)i; return(s); } main() { float sum; sum=Fcount(50)+Fcount(100)+Fcount(150)+Fcount(200); printf(″sum=%f″,sum); }

  5. 函数机制的优点 • 使程序变得更简短而清晰 • 有利于程序维护 • 可以提高程序开发的效率 • 提高了代码的重用性

  6. 项目五 根据条件进行学生成绩汇总 项目要求 一个班有40位学生(分成五个组,但每个组的人数不一样)参加了期终考试(考了三门课,分别是数学、语文、英语),老师想统计以下信息: 1、统计小组一门课程的总分及平均分; 2、统计小组若干门课程的总分及平均分; 3、输出排序后小组三门课成绩单。 设计一个菜单,通过输入1-3的编号进行选择完成不同的操作。

  7. 任务1 统计小组一门课程的总分及平均分 一、问题情景 一个班有40位学生(分成五个组,但每个组的人数不一样)参加了期终考试(考了三门课,分别是数学、语文、英语),请你用菜单的方式:求小组一门课程的总分及平均分。 分析:主函数的功能是设计一个菜单,由所选择的菜单调用相应的函数,但为了界面清晰,所以程序的执行过程中多次用一条线划界。 所以问题就归结为制作一条线的函数及求一门课程的总分及平均分。

  8. 相关知识 1.无参函数的定义形式:类型标识符 函数名( ) { 声明部分 语句 } int max( ) { int x=6,y=3,z; z= x>y?x:y; return z ; }

  9. 相关知识 (2)通过return语句来实现的。 实现形式: return(z); return z; return 后面可以是表达式, 如: 类型标识符号——函数值的类型 (1)函数值的类型:在定义函数时指定函数值的类型. int max( ); char letter( ); int max( ) { int x=6,y=3; return(x>y?x:y); }

  10. 相关知识 (3) 函数没有return语句时,返回的是一个不确定的值. printstar( ) { printf("***************\n"); } main( ) { int a; a=printstar( ); printf("a=%d\n",a); } 注意:如果在定义函数时不指定类型, 系统隐含指定函数为int型。

  11. 相关知识 (4)为了明确表示“不带回值”可用 “void” 定义“无类型” void printstar( ) { printf(“********\n”); }

  12. 函数说明语句 相关知识 无参函数的调用 函数类型 函数名() {函数体;} main() {语句; 函数名(); 语句;} 函数类型 函数名(); main() {语句; 函数名(); 语句;} 函数类型 函数名() {函数体;} 被调函数定义在主调函数之前时,可以不加以声明, 否则要先声明再使用

  13. 【例5-1】输出十行十列的星号(要求用函数调用方式解决)【例5-1】输出十行十列的星号(要求用函数调用方式解决) 方法二(主函数在后) #include "stdio.h" void pp() {printf("**********\n");} main() {int i; for(i=1;i<=10;i++) pp(); } 方法一(主函数在前) #include "stdio.h" void pp(); main() {int i; for(i=1;i<=10;i++) pp(); } void pp() {printf("**********\n");}

  14. 练习1

  15. 【例5-2】用菜单的形式分别选择百钱买百鸡,九九表,水仙花数【例5-2】用菜单的形式分别选择百钱买百鸡,九九表,水仙花数 /*乘法九九表*/ void jjb() {int i,j; printf("\n乘法九九表\n"); for(i=1;i<=9;i++) { for(j=1;j<=i;j++) printf("%-5d",i*j); printf("\n"); } } #include "stdio.h" void sxhs(); void jjb(); void bqmbj(); main() {int i; printf("1.水仙花数\n"); printf("2.乘法九九表\n"); printf("3.百钱买百鸡\n"); printf("请选择1~3的菜单:"); scanf("%d",&i); if (i==1)sxhs(); //当x=1,调用求水仙花数的函数 if (i==2)jjb(); if (i==3)bqmbj(); } /*水仙花数*/ void sxhs() { int i,a,b,c; printf("\n下列数字为水仙花数:\n"); for(i=100;i<=999;i++) { a=i/100; b=(i-a*100)/10; c=i-a*100-b*10; if (i==a*a*a+b*b*b+c*c*c) printf("%d \n",i); } } /*百钱买百鸡*/ void bqmbj() {int x,y,z; printf("公鸡数 母鸡数 小鸡数\n"); for(x=1;x<=50;x++) for(y=1;y<=33;y++) {z=100-x-y; if(2*x+3*y+0.5*z==100) printf(“%4d %4d %4d\n”, x,y,z);} }

  16. 相关知识 2. 有参函数的定义形式: eg: int max(int x,int y) { int z ; z=x>y ? x : y ; return(z); } 类型标识符 函数名(形式参数表列) { 声明部分 语句 }

  17. 相关知识 形式参数和实际参数 形参:在定义函数时,函数名后面括号中的变量名 实参:在调用函数时,函数名后面括号中的参数(表达式) int max (int x, int y) { int z; z=x>y? x:y ; return(z); } main( ) { int a,b,c; scanf(“%d,%d”,&a,&b); c=max(a,b); printf(“max is %d”,c); } x , y 为形式参数 a , b 为实际参数

  18. 相关知识 有参函数的调用 函数类型 函数名(形参列表) {函数体;} main() {语句; 函数名(实参列表); 语句;} 函数类型 函数名(形参列表); main() {语句; 函数名(实参列表); 语句;} 函数类型 函数名(形参列表) {函数体;} 被调函数定义在主调函数之前时,可以不加以声明, 否则要先声明再使用

  19. 【例5-10】编写一个函数,编写x!,在主函数中调用它。【例5-10】编写一个函数,编写x!,在主函数中调用它。 #include "stdio.h" int jc(int x) { int i,t=1; for(i=1;i<=x;i++) t=t*i; return t; } main( ) { int n; printf("请输入n的值"); scanf("%d",&n); printf("%d!=%d\n",n,jc(n)); }

  20. n 【例5-3】求Cm=m!/(n!(m-n)!) #include "stdio.h" /*阶乘的函数*/ int jc(int k) {int i; int t=1; for(i=1;i<=k;i++) t=t*i; return t; } /*主函数*/ main() {int m,n,c; printf("请输入m,n的值:"); scanf("%d%d",&m,&n); c=jc(m)/(jc(n)*jc(m-n)); printf("Cmn的值为%d\n",c); } #include "stdio.h" int jc(int k); /*函数说明语句*/ main() {int m,n,c; printf("请输入m,n的值:"); scanf("%d%d",&m,&n); c=jc(m)/(jc(n)*jc(m-n)); printf("Cmn的值为%d\n",c); } /*阶乘的函数*/ int jc(int k) {int i; int t=1; for(i=1;i<=k;i++) t=t*i; return t; }

  21. b • 2 • 3 a y x • 2 • 3 说 明 (1)实参可以是常量,变量或表达式,但必须有确定的值. max(3,a+b) (2)形参的类型必须定义,形参变量可以省略。 max(int,int); max(x,y);× (3)实参与形参的类型必须一致或赋值兼容. (4)实参同形参的数值传递是“值传递”, 由实参传给形参,不能反向,即单向传递.

  22. 3 5 3 5 x a b 传递值 y 3 temp 想一想:程序的输出结果是什么? void swap (int x, int y) { int temp; temp=x; x=y; y=temp; printf(“x=%d , y=%d \n”, x, y); } main( ) { int a=3, b=5; swap (a, b); printf(“a=%d, b=%d\n”, a, b); } x=5,y=3 a=3,b=5

  23. 任务1的具体实现 main() {int k,n,km; float sum,average; char ch; shuipx(); printf("\t班级成绩统计\n"); shuipx(); printf("1、统计小组一门课程的总分及平均分\n",n); printf("2、统计小组若干门课程的总分及平均分\n"); printf("3、输出小组排序后三门课程的成绩单\n"); printf("请输入1~3之间的一个数:"); scanf("%d",&k); shuipx(); if (k==1) {printf("请输入统计的小组的人数n="); scanf("%d",&n); shuipx(); sum=sum1(n);average=sum/n; printf("本小组的总分=%.0f\t平均分=%.1f\n",sum,average); shuipx(); } } 无参函数 #include "stdio.h" void shuipx() {printf("-------------------------------------\n"); } float sum1(int n) {int x,i; float s=0; shuipx(); printf("请输入本小组的考试成绩\n"); for(i=1;i<=n;i++) {scanf("%d",&x); s+=x;} return s; } 有参函数

  24. 练一练 1、有以下程序 fun(int a, int b) { if(a>b) return(a); else return(b); } main( ) { int x=3, y=8, r; r=fun(x,y); printf("%d\n", r); } 程序运行后的输出结果是 A)3 B)6 C)8 D)12

  25. 练一练 2、下面程序的输出是 A)1 B)2 C)8 D)10 int fun2(int x,int y) { int m=3; return(x*y-m); } main( ) { int a=7,b=5; printf(“%d\n”,fun2(a,b)/4); }

  26. 任务2 统计小组若干门课程的总分及平均分 一、问题情景 一个班有40位学生(分成五个组,但每个组的人数不一样)参加了期终考试(考了三门课,分别是数学、语文、英语),请你用菜单的方式:求小组若干门课程的总分及平均分。即完成本项目中的第二个要求。 分析: 由图可分析出主函数的功能是设计一个菜单,由所选择的菜单调用相应的函数,但为了界面清晰,所以在程序的执行过程中出现: 求小组的若干门成绩的平均分及 总分的函数又调用了一条线的函数ppp()。

  27. 函数的嵌套调用 三、相关知识 C语句不能嵌套定义函数,但可以嵌套调用函数。 也就是说在调用一个函数的过程中,又调用另一个函数。 eg:两层嵌套,其执行过程为: b函数 main 函数 a 函数 调用b函数 调用a函数 结束

  28. b函数 main 函数 a 函数 调用b函数 调用a函数 结束 想一想:输出结果是什么? b(int x) { return(x+1); } a(int m, int n) { if(m>n) return(m); else b(5); } main() { int m=3, n=8, r; r=a(m,n); printf("%d\n", r); } 6

  29. n 【例5-5】函数的嵌套调用。求C =m!/(n!(m-n)!)。 要求用函数的嵌套方式完成。 m #include "stdio.h" /*c的程序为*/ int jc(int k) {int i; int t=1; for(i=1;i<=k;i++) t=t*i; return t; } /*而B的程序为:*/ int cmn(int m,int n) { int z; z= jc(m)/(jc(n)*jc(m-n)); return z; } /*A的程序为:*/ main() { int m,n,c; printf("请输入m,n的值:"); scanf("%d%d",&m,&n); c=cmn(m,n); printf("Cmn的值为%d\n",c); } 这个程序就是A要调用B,而B要调用C,所以就称为函数的嵌套。

  30. 函数的递归调用 int f(int x) { int y,z; z=f(y); return(2+z); } 间接调用: int f1(int x) int f2(int t) {int y,z; {int a,c; z=f2(y);} c=f1(a);} 四、知识扩展 递归调用:在调用一个函数的过程中又出现直接 或间接的调用该函数本身的过程. 直接调用:

  31. 四、知识扩展 有5个人坐在一起,问第五个人几岁?他说比第4个人大2岁。问第4个人,他说比第3个人大2岁。问第3个人,他说比第2个人大2岁。问第2个人,他说比第1个人大2岁。最后问第1个人,他说是10岁。请问第5个人是多大。 求第5个人的年龄 age(5)=age(4)+2 age(4)=age(3)+2 age(3)=age(2)+2 age(2)=age(1)+2 age(1)=10 age(n)=10 (n=1) age(n)=age(n-1)+2 (n>1)

  32. 四、知识扩展 age(int n) { int c; if(n= =1) c=10; else c=age(n-1)+2; return(c); } main() { printf(“%d”,age(5)); } 运行结果: 18

  33. 四、知识扩展 age(5)=18 age(4)=16 age(5)=age(4)+2 =age(3)+2 age(3)=14 =age(2)+2 age(2)=12 =age(1)+2 =10

  34. 汉诺塔是一种古老的数学问题,是指在“A”柱上从下向上依次放着从大到小的一叠盘子,要把该柱上的盘子全部搬到指定的 “C”柱,在搬运过程中,可以利用“B”柱来协助搬移,但每次只允许移动一个盘子,且在移动过程中始终保持大盘在下,小盘在上。试问怎样搬移盘子?最少需要搬几次才能把“A”柱上的全部盘子移至“C”柱? A B C 汉诺塔

  35. void move(char x,char y) { printf(“%c- - >%c\n”,x,y); } main() {int m; printf(“input the number of diskes:”); scanf(“%d”,&m); printf(“the step to moving %3d diskes:\n”,m); hanoi(m,’A’,’B’,’C’); }

  36. A B C 需要搬的盘子的个数 借助位置 起始位置 目的地 将n个盘从A座借助B座,移到C座 void hanoi(int n,char A,char B,char C) {if(n==1)move(A,C);

  37. A B C 需要搬的盘子的个数 借助位置 起始位置 目的地 将n个盘从A座借助B座,移到C座 void hanoi(int n,char A,char B,char C) {if(n==1)move(A,C); else{ hanoi(n-1,A,C,B);

  38. A B C 需要搬的盘子的个数 借助位置 起始位置 目的地 将n个盘从A座借助B座,移到C座 void hanoi(int n,char A,char B,char C) {if(n==1)move(A,C); else{ hanoi(n-1,A,C,B); move(A,C);

  39. A B C 需要搬的盘子的个数 借助位置 起始位置 目的地 将n个盘从A座借助B座,移到C座 void hanoi(int n,char A,char B,char C) {if(n==1)move(A,C); else{ hanoi(n-1,A,C,B); move(A,C); hanoi(n-1,B,A,C); } }

  40. #include <stdio.h> int i=0; void move(char x,char y) { printf("%c- - >%c\n",x,y); i++; } void hanoi(int n,char A,char B,char C) { if(n==1) move(A,C); else { hanoi(n-1,A,C,B); move(A,C); hanoi(n-1,B,A,C); } } main() { int m; printf("input the number of diskes:"); scanf("%d",&m); printf("the step to moving %3d diskes:\n",m); hanoi(m,'A','B','C'); printf("至少需要搬%d次\n",i); }

  41. 从例题中可以看到,有些问题,采用递归的方法解决,会变得非常简单,且源程序也很简洁。从例题中可以看到,有些问题,采用递归的方法解决,会变得非常简单,且源程序也很简洁。 一个问题要采用递归的方法解决时,要符合以下条件: 1、可以把一个问题转化为一个新问题,而新问题的解决方案仍与原问题相同,只是问题的规模不同。它们只是有规律的递增或递减。 2、可以通过转化过程使问题得到解决。 3、必须有一个明确的结束递归的条件。

  42. 1.函数的嵌套调用: 在调用一个函数的过程中,又调用另一个函数。 2.函数的递归调用: 在调用一个函数的过程中,又调用它本身。

  43. 1.分析以下程序运行结果_____ ____。 #include<stdio.h> int func(int n) { if(n= =1) return 1; else return(n*func(n-1)) ; } void main() { int x; x=func(5); printf(“%d\n”,x); } 答 案 D 100 5 1 120 对不起!答错了! 对不起!答错了! 对不起!答错了! 恭喜您!答对了!

  44. 任务3 输出排序后小组三门课成绩单 一、问题情景 一个班有40位学生参加了期终考试(考了三门课),请输出学生排序后的成绩单。 分析:本项目要完成的功能相对比较多,为了使程序的结构清晰,我们可以将些项目进行分解: A:完成三门课成绩的输入;B:计算每个同学的总分与平均分;C:对三门课的成绩进行排序;D:输出函数 E:总负责,调用A、B、C、D即可。 新的知识点是:数组作为函数参数时,是如何传递的。

  45. (三)相关知识 使用数组名作为函数参数时,实参与形参都应使用数组名(或指针变量,见项目六)。当数组名作为函数实参时,不是把数组的值传递给形参,而是把实参数组的起始地址传递给形参数组,实参和形参的地址是相同的,即当形参的值发生变化时,实参的值也发生了变化。 【例5-7】有二个学生A,B合力完成下面一个问题:求20个学生的平均成绩。他们的分工是这样的: B完成20个数的平均值,不负责数据的输入; A完成20个数的输入,然后问B要20个数的平均值后输出。

  46. (三)相关知识 /*A所完成的程序*/ main() { int i,a[20]; float avg; printf("请输入20个同学的成绩\n"); for (i=0;i<20;i++) scanf("%d",&a[i]); avg=average(a); printf("这些同学的平均分为%.1f\n",avg); } #include "stdio.h" /*B所完成的程序*/ float average(int b[20]) { int i,s; float avg; s=0; for (i=0;i<20;i++) s=s+b[i]; avg=s/20.0; return avg; }

  47. 注 意 (1)数组名作为函数参数,应该在主调函数和被调函数中分别定义数组, 如上面程序中的b是形参数组,a是实参数组,分别在其所在的函数中定义。 #include "stdio.h" float average(intb[ ],intn) {int i,s; float avg; s=0; for (i=0;i<n;i++) s=s+b[i]; avg=(float)s/n; return avg; } (2)实参数组与形参数组类型应当相同,如果不同,将会出错,如上面程序中的形参数组b是整型,实参数组a也是整型。 (3) 实参数组与形参数组大小可以不同也可以相同,C编译器对形参数组大小不做检查,只是将实参数组的首地址传递给形参数组。 如上面程序中的float average(int b[20])改为float average(int b[10]),并不影响程序的正常运行,最后的结果也是相同的,我们甚至可以写成float average(int b[ ]),即只要b是数组即可。 (4)形参数组也可不指定大小,或者在被调函数中另设一个参数,来传递数组的大小。如上面的程序可改为: (5)形参数组与实参数组是占用同一个地址,所以是地址传递,即当形参的值发生变化时,实参的值也会跟着变化。

More Related