1 / 100

第 8 章函数

第 8 章函数. 本章主要内容. 函数的 基本概念 数组作为函数参数 函数的嵌套调用和递归调用 变量的作用域和存储方法 内部函数和外部函数. 由 C 程序结构所知,一个 C 程序由一个或多个源程序文件组成。. C 程序的结构:. 一个源程序文件有且仅由一个 main 的函数和若干个其它函数组成,并从 main 函数开始执行,调用其他函数后流程回到 main( ) 函数,在 main( ) 函数结尾结束整个程序的运行。.

theta
Télécharger la présentation

第 8 章函数

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

  2. 本章主要内容 • 函数的基本概念 • 数组作为函数参数 • 函数的嵌套调用和递归调用 • 变量的作用域和存储方法 • 内部函数和外部函数

  3. 由C程序结构所知,一个C程序由一个或多个源程序文件组成。由C程序结构所知,一个C程序由一个或多个源程序文件组成。 C程序的结构: • 一个源程序文件有且仅由一个main的函数和若干个其它函数组成,并从main函数开始执行,调用其他函数后流程回到main( )函数,在main( )函数结尾结束整个程序的运行。 • C程序的设计采用自顶向下、逐步细化和模块化的设计方法。每个模块实现一个特定的功能,在C语言中用函数来实现模块的功能。将程序分块设计的好处在于方便程序员进行代码检查和修改,使C程序结构清晰,功能明了,结构性强。 用户自己定义的函数是本章学习的重点内容。

  4. 说明: 1) 在C语言中,程序总是从主函数开始执行,调用完其它函数后,最终在主函数中结束,而无论主函数在程序中的位置如何。 2)函数不可以嵌套定义,但可以相互调用。 ☆主函数(main( ))调用其它函数,main()由系统调用; ☆所有函数在定义时是并列的; ☆在调用时是纵向; ☆可相互调用,也可被多次调用。

  5. [例1]编写一个求x3的函数,并在主函数中调用该函数[例1]编写一个求x3的函数,并在主函数中调用该函数 #include "stdio.h" float cube(float x) { return (x*x*x); } int main( ) { float x, y; printf("Please input x:\n"); scanf("%f", &x); y=cube(x); printf("The cube of %6.2f is %6.2f\n", x, y); return 0; } 调用求X3的函数cube(x)

  6. 8.1 函数的基本概念 8.1.1 函数的概念 函数是按规定格式书写的能完成特定功能的一段程序。 从用户使用的角度看,函数有两种: ①标准函数,即库函数。这是由系统提供的,用户不必自己定义这些函数,可以直接使用它们。应该说明,不同的C系统提供的库函数的数量和功能会有一些不同,当然许多基本的函数是共同的。见教材后面的函数表。 ② 用户自己定义的函数。用以解决用户的专门需要,由编程者自己编写代码。 用户自己定义的函数是本章学习的重点内容。

  7. int f1() { …… .. } int f2(int a, int b) { …… .. } 函数定义示意图

  8. 8.1.2 函数的定义 函数定义的一般形式: [类型说明符] 函数名(形式参数声明) { [说明与定义部分]; 函数体语句; } float cube(float x) { return (x*x*x); } 如

  9. 说明: 1) 函数名的命名规则与变量的命名规则相同,它用来唯一标识一个函数。 2) 当形式参数声明(简称形参表)中有多个形参时,每个形参之间用逗号隔开。形参表也可以是空的,但此时函数名后的括号不能省略。 有参数传递 如 double sum(float a, float b, float c) { …} 无参数传递 又如: disp ( ) { printf("How are you !\n"); }

  10. 3) 函数名前面的类型说明符指明了函数的类型。类型说明缺省 时,系统默认为函数的类型为int型。用{ }括起来的部分是函数体,由变量定义部分和语句组成。 例如: [例如] int max (int x,int y) { int z; z=x>y?x:y; return z; } 用{ }括起来的部分是函数体 /*函数体中变量的说明*/ 4)return后面的值作为函数带回的值(称函数返回值)。

  11. 5) 函数体中可以既无变量,也无语句,但一对花括号不可省略,此时构成空函数。 空函数的定义形式 类型标识符 函数名( ) { } 例如:dummy( ) { } 特点:调用后什么也不做 用处:建立程序结构,该空函数在需要时补充

  12. [例2 ]求任意圆的面积,半径r由主函数输入。 #define PI 3.14159 float area(float r) { float s; s=PI*r*r; return s; } int main() {float a; scanf("%f",&a); printf("%6.3f\n",area(a)); return 0; }

  13. void dig_to_str(int n) { char string[10]; int i=0; if(n<0) {putchar('-'); n=-n; } while(n) { string[i++]=n%10+'0'; n/=10; } while(--i>=0) putchar(string[i]); } [例3]编写函数:将一个给定的整数转换成相应的字符串后显示出来。 对负数进行处理 #include <stdio.h> int main( ) { int x; scanf("%d",&x); printf("The converted string: "); dig_to_str(x); return 0; } 将分离的数转换成字符并存入字符数组 该函数代码在哪?

  14. 8.1.3 函数的调用 函数调用的一般形式为: 函数名(实参参数表列); 或:函数名(); 1)多个实参间用逗号隔开,如:max(a,b); 2)实参与形参间个数相等,类型应一致 3)实参与形参按顺序对应,一一传递数据 4)实参可以是常量、有值的变量或表达式,如: max(3,a+b); 关于形参与实参的说明:

  15. 5)在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。只有在发生函数调用时,函数中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放。5)在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。只有在发生函数调用时,函数中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放。 6)实参表求值的顺序与系统有关。有的系统按照自右向左的顺序计算,而有的系统则相反。 int main( ) { float x; float ppp(float x); scanf("%f",&x); printf("%f",ppp(x)); return 0; } float ppp(float x) { float t; t=x*x*x; return t; }

  16. [例4] 实参表求值顺序的影响。 int sum(int x, int y) { return(x+y); } int main( ) { int a=6, b; b=sum(a, a+=4); printf("b=%d\n", b); return 0; }

  17. 8.1.4函数参数的传递方式 在函数调用时,将实参的值传递给形参变量,这种传递方式即为值传递。 1.值传递 2.地址传递

  18. 1.值传递 :在函数调用时,将实参的值传递给形参变量,这种传递方式即为值传递。 [例5] 分析以下程序的运行结果 void add(int a, int b) { a+=3; b+=6; printf(“a=%d, b=%d\n”, a,b ); } in( ) { int x=1, y=2; void add(int a, int b); add(x, y); printf("x=%d,y=%d\n", x, y); } 主函数 被调用函数

  19. 8.1.4函数参数的传递方式 调用函数时,将实参的地址传递给形参。这样实参和形参指向同一个内存单元。形参存储单元内容的变化会影响到实参。 1.值传递 2.地址传递 ?

  20. [例6] 统计单词个数 #include <stdio.h> int wordnumber(char ch[]) { char c; int i=0,word=0,n=0; while( (c=ch[i])!='\0') { if (c==' ') word=0; else if(word==0) {word=1;n++; } i++; } return n; } int main() { char s[80]; gets(s); printf("words numbers:%d\n",wordnumber(s)); return 0; } 主函数

  21. [例7] 分析以下程序的运行结果 int main() { int score[10]={87,98,95,84,86,77,79, 88,4,69}; float average(int a[]); printf("average=%5.1f\n",average(score)); return 0; } 数组名做实参,数组首地址 float average(int a[]) { float ave ,s=0; int i; for(i=0;i<10;i++) s+=a[i]; ave=s/10; return ave; }

  22. void add(int *a, int *b) { *a+=3; *b+=6; printf(“a=%d, b=%d\n”, *a,*b); } main( ) { int x=1, y=2; add(&x, &y); printf(“x=%d, y=%d\n”, x, y); }

  23. void cop(int *p) { *p=10; } int main() { int a=6; printf("before a=%d\n",a); cop(&a); printf("after a=%d\n",a); return 0; } [例8] 分析以下程序的运行结果

  24. 8.1.5 函数的返回值 定义 通过函数调用使主调函数得到一个确定的值, 称为函数的返回值。 例如: c=max(3, 5); 此时函数的返回值是5,因此c=5。 2 . 函数的返回值语句return return语句的一般形式: return (表达式);或return 表达式; 说明: 1) return语句有两重作用:即从函数中退出,返回到调用函数中并向调用函数返回一个确定的值。

  25. 2) 一个函数可以有一个以上的return语句 。 fun(int x) { if(x>1) return 2*x+1; else if(x>=0) return x* x; else return 3*x–10; } return 语句后面的括弧可以省略。 例如: return z ; 4)当函数有返回值时,凡是允许表达式出现的地方,都可以调用该函数。例如: s=cube(n)+cube(n+6);

  26. 5) 函数定义时应该指定函数的类型,应该与return语句的类型一致。如果函数类型和return语句的类型不一致,以函数类型为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。 6) 如果被调用函数没有return语句,带回一个不确定的值。如果函数不返回值,可以将函数定义为“空类型”void。例如: void printstar( )

  27. [例9] 用函数计算浮点数x的n次方(其中n为int型, n>=0)并在主函数中调用它。 double power(double x, int n) { double p; int i; for(p=i=1;i<=n;i++) p=p*x; return p; } void main() { printf(“%lf”, power(3,5)); }

  28. 8.1.6 函数的原型声明 通常,在调用函数之前,要在调用函数中对被调用函数进行声明,即通知编译系统有关函数返回类型的信息。 函数原型声明的一般形式: 类型标识符  被调函数名( ); 例如,在主函数中调用power函数时,可进行如下声明: main() { double power(); printf(“%lf”, power(3,5)); }

  29. [例10] int main() { float add(float x, float y); float a, b, c; scanf("%f%f",&a, &b); c= add(a, b) ; printf(" sum is %f ", c); return 0; } float add (float x, float y) { float z; z=x+y; return z; } /*对被调用函数的说明*/ 函数作为表达式 被调用 /*定义add函数*/ 运行结果: 3.6, 5.5 sum is 9.100000

  30. 1)注意区分函数“定义”与“声明”。函数的定义是确定函数的功能,包括函数名,函数值类型,形参及类型和函数体全部内容。函数的声明只是对要被调用的函数的返回值的类型进行说明,它只包括函数名和函数类型,不包括形参和函数体。1)注意区分函数“定义”与“声明”。函数的定义是确定函数的功能,包括函数名,函数值类型,形参及类型和函数体全部内容。函数的声明只是对要被调用的函数的返回值的类型进行说明,它只包括函数名和函数类型,不包括形参和函数体。 2)现代风格的程序设计采用如下的函数声明形式: [类型说明符] 函数名(类型说明符 [形参1],……,类型说明符 [形参n]); 例如: float fun(float x, float y, int z); 也可写为: float fun(float, float, int); 说明:

  31. 3) 下列情况下不必在调用函数前对函数进行类型说明: 如果函数的返回值是整型或字符型,系统自动按整型说明。如: main( ) { int x=1,y=3; printf("%d+%d=%d\n", x, y, sum(x,y)); } sum(int a, int b) { return (a+b); } 直接调用,不需函数说明 整型函数

  32. 被调用函数出现在调用函数之前。例如: float add (float x, float y) { float z; z=x+y; return (z); } main( ) { float add(); float a, b, c; scanf(“ %f, %f, “&a, &b); c=printf(“ sum is %f “, add(a, b) ); } 被调函数在调用 函数前定义 此处可以不说明

  33. 如果已在所有函数定义之前,在文件的开头,在函数的外部已说明了函数类型,则在各个调用函数中不必对所调用的函数再做说明。如果已在所有函数定义之前,在文件的开头,在函数的外部已说明了函数类型,则在各个调用函数中不必对所调用的函数再做说明。 如: char letter( ); float f( ); int i( ); main( ) { ……. } char letter (char c1, char c2) { ……. } 在所有函数之前 说明函数类型 此处不必说明 定义letter函数

  34. float f(float x,float y) { ……… } int fun (float j, float k ) { ………. } 定义f函数 定义fun 函数

  35. # include “stdio.h” /*调用输入输出函数*/ # include “math.h” /*调用数学函数*/ # include “string.h” /*调用字符,字符串函数*/ # include “graphics.h” /*调用图形函数*/ 库函数及调用 库函数:由人们根据需要编制并提供给用户使用的一些基本函数,在用户定义的函数中常常调用这些函数。 方法:在文件的开头用#include命令将需要的库函数包含到文件中。

  36. 8.2 数组作函数参数 • 数组元素可以作函数的实参 • 由于表达式可以做实参,数组元素可以作为表达式的组成部分,因此,数组元素可以做函数的实参,并且可以单向传递给形参。 • 例如:int a[10]; • ······ • x=power( a[6],5); • 数组名可以作函数的实参和形参 • 多维数组可以作函数参数

  37. 8.2.1一维数组作函数参数 一维数组作函数参数,形参的写法为: 类型说明符 形参数组名[数组长度 ] 例如: float average(float array[20]) { … }

  38. [例11] 趣味提高题:判断字符串是否是回文数 #include <stdio.h> int fun(char str[]) { int n,k,flag=1; for(n=0;(str[n]!='\0');n++); for(k=0;k<n/2;k++) if(str[k]!=str[n-k-1]) { flag=0;break;} return flag; } int main() { char s[80]; gets(s); if(fun(s)) printf("%s是回文数\n",s); else printf("%s不是回文数\n",s); return 0; }

  39. [例12] 写函数:打印整型一维数组的n个元素 void print_array( int a[ ], int n) { int i; for(i=0;i<n; i++) printf(“%3d”, a[i]); } [例13] 写一函数求n元数组的平均值 double average(int a[ ], int n) { int i; int s=0; for(i=0; i<n; i++) s=s+a[i]; return (double)s/n; }

  40. [例14] 写函数求字符串长度 len(char s[ ]) { int i=0; for( ; s[i]; i++) ; return i; }

  41. [例15] 阅读如下程序,给出打印结果 void swap( int a[ ]) { int t; t=a[0]; a[0]=a[1]; a[1]=t; } main( ) { int b[2]={1,2} ; swap(b); printf(“b[0]=%d,b[1]=%d\n”,b[0],b[1]); }

  42. 8.2.2二维数组作函数参数 二维数组作函数参数,形参的写法为: 类型说明符 形参数组名[ 数组长度1 ][数组长度2] 例如: srh_min(int a[3][4]) { … } 或: srh_min(a) int a[3][4]; { … }

  43. 说明: 形参数组定义时可以指定或省略第一维的大小。 例如: srh_min(int a[ ][4],int n) { … } 或: srh_min(a,n) int a[ ][4],n; { … }

  44. [例16 ]写函数交换任意一个n*6的二维数组的i,j两行 void exchange(int a[ ][6], int i,int j) { int k, t; for(k=0;k<6;k++) { t=a[i][k]; a[i][k]=a[j][k]; a[j][k]=t;} }

  45. [例17] 写函数打印n行6列二维数组,其中n是任意整数 void print_array(int a[ ][6], int n) { int i, j; for(i=0;i<n; i++) for(j=0;j<6;j++) printf(“%3d”, a[i][j]); printf(“\n”); }

  46. [例18] n行10列int型数组的每一行都有一个最大值,写一函数,求这n个最大值的最小值. max_element(int a[ ],int m) { int max, i; max= a[0]; for(i=1;i<m;i++) if(a[i]>max) max=a[i]; return max; }

  47. max_min( int a[ ], int n) { int i,min, max; min=max_element(a[0], 10); for(i=1;i<n;i++) { max=max_element(x[i],10); if(min>max) min=max; } return min; }

  48. 8.2.3数组作为函数参数的函数调用方式 数组做函数参数时,实参应用数组名。 例如: print_array(a, n); exchange(array, 3, 6); 说明: 1)数组做函数参数时,实参和形参应在调用函数和被调用函数中分别定义。 2)实参数组和形参数组类型应一致,大小可以不一致。

  49. [例19]用函数求5行5列数组主对角线最小值,元素从主函数键盘输入。[例19]用函数求5行5列数组主对角线最小值,元素从主函数键盘输入。 int main() { int a[5][5],i,j,min; for(i=0;i<5;i++) for(j=0;j<5;j++) scanf("%d",&a[i][j]); for(i=0;i<5;i++) { for(j=0;j<5;j++) printf("%-4d",a[i][j]); printf("\n"); } min=funmin(a); printf("%d\n",min); return 0; } #include <stdio.h> int funmin(int b[5][5]) { int i,min; min=b[0][0]; for(i=0;i<5;i++) if (min>b[i][i]) min=b[i][i]; return min; }

  50. [例20] 请编写函数 int fun(char str [ ]), 它的功能是判别字符串str是否是“回文”, 若是,返回 1,否则返回 0。(提示:回文是指正反序相同,例如,“13531”、“helleh”是回文, 但 “1353”、“Helleh” 不是回文。) 分析:假设已知字符串的长度为n,检查回文的算法可设计如下: 第0个字符和第n–1个字符比较,不相等则不是回文,相等则继续进行下面的操作; 第1个字符和第n–2个字符比较,不相等则不是回文,相等则继续进行下面的操作; …… 第n/2–1个字符和第n–1–(n/2–1)个字符比较,不相等则不是回文,相等则是回文。

More Related