1 / 77

第 7 章 函数

第 7 章 函数. 第 7 章 函数. 7.1 函数的基本概念 7.2 使用函数编写程序 7.3 数组作为函数参数 7.4 变量的生命周期与作用域 7.5 递归与递归函数. 本章要点. 怎样定义函数?如何调用函数?如何声明函数? 什么是函数的参数?在函数调用时,参数是如何传递的? 在使用函数的过程中,要注意哪些问题? 如何使用局部变量和全局变量? 什么是静态局部变量? 递归的定义与调用. 为什么使用函数. int main() { :::::: x=x*x*x; y=y*y*y; z=z*z*z;

knut
Télécharger la présentation

第 7 章 函数

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. 第7章 函数

  2. 第7章 函数 7.1 函数的基本概念 7.2 使用函数编写程序 7.3 数组作为函数参数 7.4 变量的生命周期与作用域 7.5 递归与递归函数

  3. 本章要点 • 怎样定义函数?如何调用函数?如何声明函数? • 什么是函数的参数?在函数调用时,参数是如何传递的? • 在使用函数的过程中,要注意哪些问题? • 如何使用局部变量和全局变量? • 什么是静态局部变量? • 递归的定义与调用

  4. 为什么使用函数 int 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; ::::: } int main() { :::::: ans1=cube(x,y,z); ans2=cube(a,b,c); ::::: } 重复多次的同一计算类型 int cube(int a,int b, int c) { int ans; ans=(a*a*a)+(b*b*b)+(c*c*c); return ans; } ans 函数 main函数 函数可以把相对独立的某个功能抽象出来,使之成为程序中的一个独立实体。可以在同一个程序或其他程序中多次重复使用

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

  6. 标准库函数和自定义函数 标准库函数: • 由C语言系统提供; • 用户无须定义,也不必在程序中作类型说明; • 只需在程序前包含有该函数定义的头文件。 自定义函数: • 用户在程序中根据需要而编写的函数。

  7. 7.1 函数的基本概念 7.1.1 求最大值 7.1.2 函数的定义 7.1.3 函数的调用 7.1.4 参数的按值传递机制

  8. 7.1.1 求最大值 试试看:从键盘输入三个整数a、b、c,求出其中的最大值。定义一个计算最大值的函数max(a,b),返回a,b的最大值。 思路分析:三个整数求最大值,两两判断。 if( a > b) max = a; else max = b;

  9. 回顾我们在第三章所学的内容 int main() { int a,b,c,z,maxi; scanf("%d%d%d",&a,&b,&c); if( a>b) z=a; else z=b; if( z>c) maxi=z; else maxi=c; printf("max=%d\n",maxi); return 0; } 程序7-1 #include "stdio.h" int main(void) { int a, b, c, z, maxi; int max(int a, int b);scanf("%d%d%d",&a,&b,&c); z = max(a, b); //函数调用maxi = max(z, c); printf("max=%d\n", maxi); return 0; } 定义一个计算最大值的函数max(a,b),返回a,b的最大值。 int max (int a, int b) /* 函数首部 */ { if( a > b) return a; else return b; }

  10. 7.1.2 函数的定义 • 函数是指完成一个特定工作的独立程序模块,包括有标准库函数和用户自定义函数。 • 库函数:由C语言系统提供定义 如scanf()、printf()、sqrt( )等函数 • 自定义函数:需要用户自己定义 如求最大值的函数max(a,b) • main()也是一个函数,C程序由一个或多个函数构成,有且仅有一个main()函数。

  11. 程序中一旦调用了某个函数,该函数就会完成一些特定的工作,然后返回到调用它的地方。程序中一旦调用了某个函数,该函数就会完成一些特定的工作,然后返回到调用它的地方。 • 有返回值函数:函数经过运算,得到一个明确的运算结果,并需要回送该结果。例如,函数max(a,b)返回a,b的最大值。 • 无返回值函数:函数完成一系列操作步骤,不需要回送任何运算结果。

  12. 函数类型 函数名(形参表)/* 函数首部 */ { /* 函数体 */ 函数实现过程 return 表达式; } 1.有返回值的函数定义 函数返回值的类型 没有分号 只能返回一个值 把函数运算的结果回送给主函数

  13. 类型1 参数1 ,类型2 参数2 ,……,类型n 参数n 参数之间用逗号分隔,每个参数前面的类型都必须分别写明 形参 int max (int a, int b) /* 函数首部 */ { if( a > b) return a; else return b; } 函数类型 函数名(形参表){ 函数实现过程 return 表达式; }

  14. int max (int a, int b) /* 函数首部*/ {/* 函数体,写在一对大括号内 */ if( a>b) return a; else return b; /* 返回运算结果*/ } 分析函数的定义 函数类型 函数名 形参表 与函数类型一致

  15. void函数名(参数表) /* 函数首部 */ { /* 函数体 */ 函数实现过程 return; /* 可以省略return */ } 2.无返回值的函数定义 这类函数通常用于屏幕输出等 表示不返回结果 不能省略,否则函数类型被默认定义为int

  16. 试试看:输出一个n行的直角三角形 * ** *** **** ***** void prt (int n) { int i; for (i = 1; i <= n; i++) printf("*"); putchar ('\n'); } 程序7-2 #include <stdio.h> int main (void) { int i, n; void prt (int n); scanf("%d", &n); for(i = 1;i <= n;i++) prt(i); return 0; }

  17. 7.1.3 函数的调用 • 定义一个函数后,就可以在程序中调用这个函数。 • 调用标准库函数时,在程序的最前面用#include命令包含相应的头文件。 • 调用自定义函数时,程序中必须有与调用函数相对应的函数定义。 • 切记:实参的个数、类型和顺序,应该与被调用函数所要求的参数个数、类型和顺序一致,才能正确地进行数据传递。

  18. 使用返回值: z=max(a,b); 完成操作: prt(i); 1.函数调用的形式和过程 函数名(实参表) 常量、变量、表达式 常用于有返回值的函数的调用 常用于void类型函数的调用

  19. 计算机在执行程序时,从main函数开始执行,如果遇到某个函数调用,main函数被暂停执行,转而执行相应的函数,该函数执行完后,将返回main函数,然后再从原先暂停的位置继续执行。计算机在执行程序时,从main函数开始执行,如果遇到某个函数调用,main函数被暂停执行,转而执行相应的函数,该函数执行完后,将返回main函数,然后再从原先暂停的位置继续执行。 • 函数遇return或最后的右大括号,返回主函数。

  20. 分析函数调用的过程 #include <stdio.h> int main() { int a,b,c,z,maxi; int max(int a,int b); scanf("%d%d%d",&a,&b,&c); z=max(a,b); maxi=max(z,c); printf("max=%d\n",maxi); return 0; } int max (int a, int b) { if( a>b) return a; else return b; } 到VC中单步执行该程序 注意F10和F11的区别:F11可进入子函数跟踪,F10把子函数作为一个语句一次执行完。 调用函数 实参形参 执行函数中的语句 返回调用它的地方

  21. 函数嵌套调用 void f1() { :::::::: f2(); :::::::: } #include<stdio.h> void main() { ::::::::: f1(); :::::::: :::::::: } void f2() { ::::::::: ::::::::: } 从一个函数调用另一个函数称为函数的嵌套调用

  22. 函数递归调用 /* 此函数用于计算 a 的阶乘 */ int factorial(int a) { if (a == 1) return 1; else { a = a * factorial(a-1); return a; } } 在一个函数体内调用自身称为函数的递归调用

  23. 函数类型 函数名(参数表); int max( int a, int b); void prt ( int n); 函数必须先定义后调用,将主调函数放在被调函数的后面,就像变量先定义后使用一样。 如果自定义函数在主调函数的后面,就需要在函数调用前,加上函数原型声明。 函数声明:说明函数的类型和参数的情况,以保证程序编译时能判断对该函数的调用是否正确。 2.函数原型声明 只写函数定义中的第1行(函数首部),并以分号结束。

  24. 3.函数结果返回 • 函数返回的两种情况 • 完成确定的运算,有一个运算结果返回给主调函数。 • 完成指定工作,没有确定的运算结果需返回给主调函数(函数类型void)。 • 函数结果返回的形式: • return 表达式; • return (表达式);

  25. 7.1.4 按值传递机制 • 函数定义时的参数被称为形式参数(简称形参) int max(int a, int b); • 函数调用时的参数被称为实际参数(简称实参) z=max(a, b); • 实参形参 • 在参数传递过程中,实参把值复制给形参。 • 形参和实参一一对应:数量一致,类型一致,顺序一致 • 形参:变量,用于接受实参传递过来的值 • 实参:常量、变量或表达式 单向传递

  26. 7.2 使用函数编写程序 7.2.1 素数表 7.2.2 验证哥德巴赫猜想 7.2.3 组合数

  27. 7.2.1 素数表 解决问题:输出100以内的全部素数,每个素数占6列。要求定义和调用函数prime (m)判断m是否为素数,当m为素数时返回1,否则返回0。 思路分析:对2~100之间的每个数进行判断,若是素数,则输出该数。 for(m = 2; m <= 100; m++) if (m是素数) printf("%6d", m);

  28. 回顾我们在第四章所学的内容 for(m=2; m<=100; m++) { n=sqrt(m);flag=1; for(i=2; i<=n; i++) { if(m%i==0) { flag=0; break; } } if(flag!=0)printf("%6d", m); } 判断m是否是素数,若是则输出m

  29. #include <stdio.h> #include <math.h> int main(void) { int m; int prime (int m); for(m = 2; m <= 100; m++) { if ( prime(m) != 0 ) printf("%6d", m ); } printf ("\n"); return 0; } 程序7-3 int prime (int m) { int i, n; if ( m == 1 ) return0; n = (int)sqrt (m); for( i = 2; i <= n; i++) { if (m % i == 0) return0; } return1; }

  30. 7.2.2 验证哥德巴赫猜想 解决问题:验证哥德巴赫猜想,任意输入一个不小于6的偶数,将其表示成两个素数的和,如: 6=3+3;8=3+5;18=7+13 思路分析: 该问题可以通过调用7-3中的prime函数来实现。因为每个偶数都可以分解为两个奇数之和,所以调用两次prime函数就能方便的判断出这两个奇数是否全部为素数,如果是,结论即成立,如果不是,则继续判断下一组奇数。

  31. 程序7-4 int main() { int even, i; scanf("%d", &even); for(i = 3;i <= even/2;i = i+2) if(prime(i) && prime(even-i)) printf("%d %d\n", i, even-i); return 0; } #include <stdio.h> #include <math.h> int prime (int m) { int i, n; if ( m == 1 ) return 0; n = (int)sqrt (m); for( i = 2; i <= n; i++) { if (m % i == 0) return 0; } return 1; }

  32. 7.2.3 组合数 “组合”是一个数学名词,是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序的因素,它源于人们对于客观世界中存在的数与形及其关系的发现和认识。我们的祖先在很早就开始研究组合问题了。例如,《易经》中用十个天干和十二个地支以六十为周期来记载月和年,以及杨辉三角。我们在小时候经常玩的七巧板,用7块小小的积木可以拼出259种图形,其实也是一个组合问题。

  33. 7.2.3 组合数 解决问题:编写计算组合数的程序 求阶乘: unsigned long fact(unsigned int n) { unsigned int i; unsigned long result = 1; for(i = 2; i <= n; i++) result *= i; return result; }

  34. 程序7-5 #include “stdio.h” int main(void) { int m, k; double p; scanf(“%d%d”, &m, &k); p=(double)fact(m) / (fact(k) * fact(m - k)); printf(“p=%.0f\n”, p); return 0; }

  35. 7.3 数组作为函数参数 7.3.1 最大进制数 7.3.2 数组做函数参数 7.3.3 形参数组的实质 7.3.4 多个二进制数排序 7.3.5 集合的合并——利用有序关系简化问题

  36. 7.3.1 最大进制数 解决问题:输入n个非负整数,每个数的进制由其后面的数字k指定,k>=2且k<=10,输出最大的数对应的十进制数。 思路分析: (1)k进制数要用字符串来存储,比如一个9位的十进制数对应的二进制数长度是30位左右,如果用%d来获取就会产生类型溢出。 (2)调用函数kToD()将K进制数转化为十进制整数。 (3)利用第四章所学的方法求出其中的最大值。

  37. 程序7-6 int main() { int i, n, k, b[50], max; char a[50]; scanf("%d", &n); for(i = 0; i < n; i++) { scanf("%s%d", a, &k); b[i] = kToD(a, k); } max = b[0]; for(i = 0; i < n; i++) { if(b[i] > max) max = b[i]; } printf("%d\n", max); return 0; } #include<stdio.h> #include<string.h> int kToD(char str[], int k) { int i, sum; sum = str[0] - '0'; for(i = 0; i<strlen(str)-1; i++) sum = sum*k+(str[i+1]-'0'); return sum; }

  38. 7.3.2 数组做函数参数 • 因为数组名代表该数组的首地址,用数组名作实参时,是以传址方式调用函数,也就是说是把实参数组的首地址赋给形参; • 实际上形参数组和实参数组为同一数组,共同拥有一段内存空间。

  39. b b[0] array b[4] 求数组元素的和 int sum (int array[ ], int n) { int i, s = 0; for(i=0; i<n; i++) s += array[i]; return(s); } int main( ) { int i; int b[5] = {1, 4, 5, 7, 9}; printf("%d\n", sum(b, 5)); return 0; } 形参数组和实参数组为同一数组,共同拥有一段内存空间 array[0] …… array[4]

  40. 7.3.3 形参数组的实质 一般变量作参数:传递的是数值,形参的值的改变不影响实参。 数组做参数:传递的是数组的首地址,形参数组和实参数组实质上是同一块内存区域,形参数组发生改变,实参数组也随之发生改变。

  41. b y a x 3 3 5 5 5 3 以下程序的运行结果? #include<stdio.h> void swap(int x, int y) { int t; t = x; x = y; y = t; } int main() { int a = 3, b = 5; swap(a, b); printf("%d %d\n", a, b); return 0; } 运行结果: 3 5

  42. 解决问题:通过函数实现n个学生成绩的排序 程序7-7: #include <stdio.h> #define N 100 void sort( double grade[ ], int n); int main() { double grade[N]; int i,n; scanf("%d", &n); for(i=0;i<n;i++) scanf("%lf",&grade[i]); sort(grade, n); printf("\n 排序后的成绩为:\n"); for(i=0;i<n;i++) printf("%5.2f ",grade[i]); printf("\n"); } void sort( double a[ ], int n) { int i,j; double temp; for(i=1;i<N;i++) { for(j=0;j<N-i; j++) { if(a[j] > a[j+1]) { temp = a[j+1]; a[j+1] = a[j]; a[j] = temp; } } } } 传递数组时形参要声明为数组(指针),并且数组长度要和实参相等,或缺省长度 传递数组时实参用数组名 对形参数组排序,就是对实参数组排序

  43. 7.3.4 多个二进制数排序 解决问题:输入三个二进制数,要求将这三个二进制数对应的十进制整数按从小到大的顺序输出。 思路分析: 可以借鉴程序7-4的kToD函数,该问题中全部为二进制数,所以可以通过对kToD函数的改写设计bToD函数。 读入三个字符串s1,s2,s3分别调用三次bToD函数得到对应的三个十进制数,对这三个十进制数排序输出。

  44. 程序7-8 #include <stdio.h> #include <string.h> #define N 32 /* 把一个二进制数转换成对应的十进制数 */ int bToD(char str[]) { int i, d; d = 0; for(i = 0; str[i] != '\0' ; i++) d = d * 2 + (str[i] – '0'); return d; }

  45. 程序7-8 int main(void) { char str1[N], str2[N], str3[N]; int a, b, c, temp; scanf("%s%s%s", str1, str2, str3); a = bToD(str1); b = bToD(str2); c = bToD(str3); if(a > b) /* 三个数两两比较排序 */ { temp = a; a = b; b = temp; } if(a > c) { temp = a; a = c; c = temp; } if(b > c) { temp = b; b = c; c = temp; } printf("%d %d %d\n", a, b, c); return 0; }

  46. 7.3.5 集合的合并——利用有序关系简化问题 解决问题:将两个整数集合A和B合并为集合C。并将集合C中元素按升序输出。你应该知道,集合中不允许有重复元素。 思路分析: 两个集合合并并且要排序,可以调用程序7-7中的sort()函数先对集合a、b分别排序,然后利用有序序列合并的思想把两者中的数据合并到集合C中,因为集合中的数据具有唯一性,所以如果a、b中有相同的数据,只保存一个。

  47. 程序7-9 #include<stdio.h> #define N 100 void sort( int a[ ], int n) { int i, j; int temp; for(i = 1; i < n; i++) /*冒泡排序*/ for(j = 0; j < n-i; j++) if(a[j] > a[j+1]) { temp = a[j+1]; a[j+1] = a[j]; a[j] = temp; } }

  48. 程序7-9 int main(void) { int i, j, k, m, n; int a[N/2], b[N/2], c[N]; scanf("%d%d", &m, &n); for(i = 0; i < m; i++) scanf("%d", &a[i]); for(i = 0; i<n; i++) scanf("%d", &b[i]); /*调用两次排序函数对两个数组进行排序,得到升序序列 */ sort(a, m); sort(b, n);

  49. 程序7-9 /* a、b数组中的元素从小到大两两比较,选择合适的数据插入到c中 */ i = 0, j = 0, k = 0; while(i < m && j < n) { if(a[i] < b[j]) /*如果a[i]<b[j],则存入a[i] */ c[k++] = a[i++]; else if(a[i] > b[j]) /*如果a[i]>b[j],则存入b[j] */ c[k++] = b[j++]; else /* 如果a[i]=b[j],则存入a[i],舍去b[j] */ { c[k++] = a[i]; i++; j++; } }

  50. 程序7-9 while(i < m) c[k++]=a[i++]; while(j < n) c[k++]=b[j++]; for(i = 0; i < k; i++) /* 输出c中的信息 */ printf("%d ", c[i]); printf("\n"); return 0; }

More Related