1 / 56

《 程序设计基础( C ) 》

《 程序设计基础( C ) 》. 第六章 函数. 本章内容. 模块化程序设计 函数说明、函数实现与函数调用 参数传递 形参、实参与返回值 传值、传址与传数组 递归函数 变量作用域与存贮类别 库函数. 一、模块化程序设计. 模块化设计思想 一个复杂问题可分解为若干个子问题 每个子问题也可以再分解为更简单的小问题 程序设计转化为层次式结构化的模块设计 自底向上 与 自顶向下 设计方法 模块特点 模块间存在调用接口(输入输出) 各模块可分别编写、测试,再进行总组装 模块可以有一定的可重用性 模块实现细节的独立性(封装). 二、函数设计.

arden-burke
Download Presentation

《 程序设计基础( C ) 》

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. 《程序设计基础(C)》 第六章 函数

  2. 本章内容 • 模块化程序设计 • 函数说明、函数实现与函数调用 • 参数传递 • 形参、实参与返回值 • 传值、传址与传数组 • 递归函数 • 变量作用域与存贮类别 • 库函数

  3. 一、模块化程序设计 • 模块化设计思想 • 一个复杂问题可分解为若干个子问题 • 每个子问题也可以再分解为更简单的小问题 • 程序设计转化为层次式结构化的模块设计 • 自底向上 与 自顶向下 设计方法 • 模块特点 • 模块间存在调用接口(输入输出) • 各模块可分别编写、测试,再进行总组装 • 模块可以有一定的可重用性 • 模块实现细节的独立性(封装)

  4. 二、函数设计 • 函数举例:素数判断 • 函数举例:数组相关 • 函数概念 • 函数声明/函数说明 • 函数调用 • 函数实现/函数定义

  5. 函数设计例1:素数 • 输入n,判断n是否为素数 • 输入n,输出n以内的所有素数 • 输入m和n,输出m与n之间所有素数,按每行7个素数的形式输出,如果没有素数,则输出None • 验证哥德巴赫猜想:将4到100的所有偶数分解为两个素数之和

  6. 判断素数的函数 • 专判素数的模块 • 函数名称:isprime • 函数声明/函数说明: • int isprime( int n ); • 自变量类型:整型 术语参数 • 结果类型: 整型 术语返回 • 功能说明:若n为素数,则返回1,若n不是素数,则返回0

  7. 第一章标志法

  8. #include <stdio.h> main() { int n, i, isyes; scanf( "%d", &n ); if ( isyes == 1 ) printf( "Yes" ); else printf( "No" ); } int isprime(int n) { int i, isyes; return isyes; } 函数剥离过程 isyes = 1; for ( i=2; i<=n-1; i++ ) if ( n%i == 0 ) isyes = 0; isyes = isprime( n );

  9. #include <stdio.h> int isprime(int n) { int i,isyes; isyes=1; for (i=2;i<=n-1;i++) if (n%i==0) isyes = 0; return isyes; } main() { int n; scanf( "%d", &n ); if ( isprime(n) ) printf( "Yes" ); else printf( "No" ); } 函数概念 函数实现 形式参数 函数调用 实际参数 局部变量 函数返回

  10. 使用return优化函数 int isprime(int n) { int i; for (i=2;i<=n-1;i++) if (n%i==0) return 0; return 1; }

  11. 将4到100的所有偶数分解为两个素数之和 main() { int n,i; for ( n=4; n<=100; n+=2 ) for ( i=2; i<n; i++ ) if ( isprime(i) && isprime(n-i) ) { printf("%2d=%2d+%2d\t",n,i,n-i); break; } }

  12. 先声明再调用 #include <stdio.h> int isprime( int n ); main() { …… } int isprime( int n ) { …… } 先实现再调用 #include <stdio.h> int isprime( int n ) { …… } main() { …… } 代码的组织顺序

  13. 函数设计规范 • 函数调用前必须先出现函数实现或函数声明 • 函数实现与函数声明必须一致 • 函数名称、参数类型及顺序、返回类型 • 函数声明中形式参数名可以省略 • 如:int isprime( int ); • 函数之间的局部变量允许重名 • 无返回值或无参数,类型记为void • 函数内部对形参的修改不影响调用函数

  14. 传递数值示例 • int func( int n ) • { • n = n + 1; /* 修改了n的值 */ • return n; • } • main() • { • int a=1, b; • b = func( a ); /* a的值不受影响 */ • printf( “a=%d,b=%d\n”, a, b ); • }

  15. 函数设计例2:数组相关 • 数组相关操作 • 计算累加和 • 计算最大值、最小值、平均值 • 排序 • 查找 • 输入、输出 • 传递数组:对数组参数的修改影响调用函数

  16. 数组累加和 • 数组累加:long sum( int a[ ], int n ); • 主函数示例 • main() • { • int x[6],i; long s; • for ( i=0; i<6; i++ ) • scanf( “%d”, &x[i] ); • s = sum( x, 6 ); • printf( “%ld\n”, s ); • }

  17. 数组累加和 long sum(int a[ ],int n) { long rst = 0; int i; for ( i = 0; i < n; i++ ) rst += a[i]; return rst; }

  18. 数组相关函数 • float average( int a[ ], int n ); • int max( int a[ ], int n ); • int min( int a[ ], int n ); • void sort( int a[ ], int n ); • int find( int a[ ], int n, int x ); • void sca( int a[ ], int n ); • void prt( int a[ ], int n );

  19. 输入数组 void sca(int a[ ], int n) { int i; for ( i=0;i<n;i++ ) scanf(“%d”,&a[i]); } 返回类型为void,省略return语句

  20. 输出数组 void prt(int a[ ], int n) { int i; for ( i=0;i<n;i++ ) printf(“%d ”, a[i]); printf( “\n” ); }

  21. 数组排序 void sort( int a[ ], int n ) { int i, j, t; for ( i = 0; i < n-1; i++ ) for ( j = 0; j < n-1-i; j++ ) if ( a[j]>a[j+1] ) { t=a[j]; a[j]=a[j+1]; a[j+1]=t; } } 对a数组的修改在函数结束后仍起作用

  22. 排序程序 • #include <stdio.h> • void sca( int a[ ], int n ) • { …… } • void prt( int a[ ], int n ); • { …… } • void sort( int a[ ], int n ) • { …… } • main() • { • int a[10]; • sca( a, 10 ); sort( a, 10 ); prt( a, 10 ); • }

  23. 参数传递上的灵活性 • 数组传递上的偏移 • prt( a, 10 ); 输出a[0]至a[9] • prt( a, 5 ); 输出a[0]至a[4] • prt( a+1, 5 ); 输出a[1]至a[5] • prt( a+4, 3 ); 输出a[4]至a[6] • 输入10个整数,对中间8个排序 • sca( a,10 ) • sort( a+1, 8 ); • prt( a, 10 );

  24. 三、参数传递 • 函数调用与返回的具体过程 • 传递数值

  25. int max(int a,int b) { int c; if ( a>b ) c = a; else c = b; return c; } main() { int x,y,z; scanf(“%d%d”,&x,&y); z=max(x,y); printf(“%d\n”,z); z=max(3,5); printf(“%d\n”,z); } 调用过程(形参、实参与返回)

  26. main函数有变量x,y,z 调用max函数时,实参为x,y,形参为a,b 实参x,y被复制到max函数的形参变量a,b max函数用形参a,b进行计算,结果放在c中 return c时,变量c的值被复制到指定寄存器,并返回main函数 main函数从指定寄存器取数送到z变量 调用过程说明

  27. 四、递归函数 • 递归函数正向设计 • 阶乘、排序 • 递归函数运行跟踪 • 阶乘 • 递归函数运行求解 • 阶乘、数列

  28. 求阶乘 n! 1 n1 n! = n * (n-1)! n>1 long jcheng(int n); 递归函数实现方法 long jcheng(int n) { long rst; if ( n <= 1 ) rst = 1; else rst = n*jcheng(n-1); return rst; } [例6.15] 递归阶乘举例

  29. 递归函数运行跟踪 • 以阶乘为例 • 计算机运行jcheng(3)的过程 • 板书分析

  30. 递归函数求解 • 简单函数:没有使用静态与全局变量,函数功能也与文件/系统无关。 • 原则:多次调用函数时如果所有参数一样,则运行结果一定一样,与调用位置无关。 • 简单递归函数:只有一个参数(多数为n),没有使用静态与全局变量。

  31. 当n=1时,可得jcheng(1)返回1。 当n=2时,计算rst = 2 * jcheng(1),由第1步可知,rst=2,故jcheng(2)返回2。 当n=3时,同理有rst =3*jcheng(2)=3*2=6,故jcheng(3)返回6。 递归函数实现方法 long jcheng(int n) { long rst; if ( n <= 1 ) rst = 1; else rst = n*jcheng(n-1); return rst; } 阶乘求解举例

  32. prtlist(0)输出“0 ”。 prtlist(1)先输出“1 ”,再调用prtlist(0),由上一步,输出“0 ”,重复一次,输出“1 ”和“0 ”,故prtlist(1)输出“1 0 1 0 ”。 prtlist(2)先输出“2 ”,再调用prtlist(1),输出“1 0 1 0 ”,重复一次,故prtlist(2)输出“2 1 0 1 0 2 1 0 1 0 ” void prtlist( int n ) { if ( n == 0 ) printf( “0 ” ); else { printf( “%d ”, n ); prtlist( n-1 ); printf( “%d ”, n ); prtlist( n-1 ); } } 数列求解举例

  33. 五、变量作用域与存贮类别 • 变量作用域 • 内存分配形式 • 存贮类别 • 动态局部变量 • 静态局部变量 • 全局变量

  34. 变量作用域 • 局部变量 • 形式参数以及在函数内部定义的变量 • 只有该函数才能访问 • 全局变量 • 在函数外部定义的变量 • 所有函数都能访问

  35. 全局变量举例 int a[10]; void scaX(void) { int i; for ( i=0;i<10;i++ ) scanf(“%d”,&a[i]); } void prtX(void) { int i; for ( i=0;i<10;i++ ) printf(“%d ”, a[i]); }

  36. void sortX(void) { int i, j, t; for ( i = 0; i < 9; i++ ) for ( j = 0; j < 9-i; j++ ) if ( a[j] < a[j+1] ) { t=a[j];a[j]=a[j+1];a[j+1]=t;} } main() { scaX(); sortX(); prtX(); }

  37. 变量在内存中安排 • 静态区段(数据段) • 所有全局变量 • 程序装入内存时安排变量地址并初始化 • 在程序运行中地址不变 • 动态区段(堆栈段) • 一般局部变量 • 在函数调用时才给变量安排地址并初始化 • 各次调用之间安排的地址可能不同 • 分配区段(堆区) 见第七章malloc函数

  38. 变量存贮类别(1) • 动态变量(auto) • 只适用于局部变量 • 在类型前加auto修饰,也可省略不写 • 如:auto int i; 或 int i; • 变量安排在动态区段 • 此前所有程序的局部变量都是动态变量

  39. 变量存贮类别(2) • 静态变量(static) • 在类型前加static修饰 • 静态局部变量 • 该变量将安排在静态区段,有固定地址,并只在程序装入时初始化一次。 • 静态全局变量 • 限制该全局变量只能被同一个源程序内的各函数所访问。

  40. int d=1; void func2(int p) { static int d=4; d+=p++; printf(“p=%d d=%d\n”, p, d); } main() { int i, a=5; for (i=0; i<2; i++) { func2(a); d+=a++; printf(“a= %dd=%d\n”, a, d); } } 【例6.24】阅读程序(全局变量和静态变量)

  41. 静态变量的作用 • 使得函数能“记住”上一次调用时的运行情况,简单智能。 • 如计算阶乘时,可从上一次结果继续乘 • 相对“稳定”的常量,不需要每次调用时都进行初始化,加快运行 • 如各月天数,static int days=[31,28,31…

  42. 变量存贮类别(3) • 外部变量(extern) • 只用于全局变量,多个源程序时使用。 • 其中一个源程序不加extern修饰 • 其它源程序都要加extern修饰 • 寄存器变量(register) • 只用于局部变量,有“可能”加快程序运行 • 可按auto理解 • 一般不建议使用

  43. 输入输出函数 stdio.h 数学函数 math.h 字符串函数 string.h 常用子程序 stdlib.h 控制台函数 conio.h 动态分配函数 malloc.h 图形函数 graphics.h 其它如: dos.h、bios.h、time.h 函数帮助(ctrl-F1) 在函数名位置上 在#include文件名上 在空白处 六、C常用库函数(附录IV)

  44. max函数:返回最大值所在下标 • int max( int a[ ], int n ) • { • int i,k=0; • for ( i=1; i<n; i++ ) • if ( a[k] < a[i] ) • k = i; • return k; • }

  45. sort函数:选择法,从大到小 • void sort( int a[ ], int n ) • { • int i,k,t; • for ( i=0; i<n-1; i++ ) • { • k = max( a+i, n-i ) + i; • if ( k!=i ) • { t=a[k]; a[k]=a[i]; a[i]=t; } • } • }

  46. find函数:查找并返回下标 • int find( int a[ ], int n, int x ) • { • int i; • for ( i=0; i<n; i++ ) • if ( a[i] == x ) • return i; • return -1; • }

  47. 统计出现次数 • int count( int a[ ], int n, int x ) • { • int ct=0, i; • for ( i=0; i<n; i++ ) • if ( a[i] == x ) • ct++; • return ct; • }

  48. 输出只出现一次的数 • void prt1( int a[ ], int n ) • { • int i; • for ( i=0; i<n; i++ ) • if ( count(a,n,a[i]) == 1 ) • printf( “%d\t”, a[i] ); • printf( “\n” ); • }

  49. 输出出现3次及以上的数 • void prt3( int a[ ], int n ) • { • int i; • for ( i=0; i<n; i++ ) • if ( count(a,i,a[i])==0 && /*a[0]至a[i-1],0次*/ • count(a+i,n-i,a[i])>=3 ) /*a[i]至a[n-1],3次*/ • printf( “%d\t”, a[i] ); • printf( “\n” ); • }

  50. 从a数组选择出现3次的数到数组b中,并返回相应个数从a数组选择出现3次的数到数组b中,并返回相应个数 • int get3( int a[ ], int n, int b[ ] ) • { • int i, k=0; • for ( i=0; i<n; i++ ) • if ( count(a,i,a[i])==0 && /*a[0]至a[i-1],0次*/ • count(a+i,n-i,a[i])>=3 ) /*a[i]至a[n-1],3次*/ • b[k++] = a[i]; • return k; • }

More Related