330 likes | 506 Views
第八章 函数. 8.1 函数概述 8.2 函数定义的一般形式 8.3 函数参数和函数的值 8.4 函数的调用 8.5 函数的嵌套调用 8.6 函数的递归调用 8.7 数组作为函数参数 8.8 局部变量和全局变量. #include <stdio.h> #include <math.h> void main ( ) { int a, b, c; scanf (“%d%d”, &a, &b) ; c=a+ abs (b); printf (“c=%d<br>”, c); }. 8.1 函数概述. 一、有关 C 函数的介绍
E N D
第八章 函数 • 8.1 函数概述 • 8.2 函数定义的一般形式 • 8.3 函数参数和函数的值 • 8.4 函数的调用 • 8.5 函数的嵌套调用 • 8.6 函数的递归调用 • 8.7 数组作为函数参数 • 8.8 局部变量和全局变量
#include <stdio.h> #include <math.h> void main( ) { int a, b, c; scanf(“%d%d”, &a, &b) ; c=a+abs(b); printf(“c=%d\n”, c); } 8.1 函数概述 • 一、有关C 函数的介绍 • 一个源程序文件由一个 • 或多个函数组成 2. 一个C程序由一个或多个 源程序文件组成 3. C程序从main函数开始执行, 调用其他函数后再返回到main 函数 4. 所有函数都是平行的, 定义函数时是互相独立的, 函数之间可以互相调用, 但是不能调用main函数
二、C 函数的分类 1. 从用户使用角度分为: 标准函数和用户自定义函数 2. 从函数的形式分为: 无参函数和有参函数 函数定义 #include <stdio.h> void main( ) { printf(“******\n”); printf(“ good \n”); printf(“******\n”); } /*printf是标准函数*/ #include <stdio.h> void list(void) { printf(“******\n”); } void main( ) { list( ) ; printf(“ good \n”); list ( );/*用户自定义 函数*/ } #include <stdio.h> int max(int x, int y) { int z ; if (x>y) z=x ; else z=y ; return(z) ; } void main( ) { int a ,b ,c ; scanf(“%d%d”,&a,&b); c=max(a,b); printf(“max=%d”,c); } 形式参数 函数调用 实在参数
8.2函数定义的一般形式 1. 定义格式 : 函数类型 函数名 ( 形式参数表) { 函数体 ; } 2. 说明 (1) 函数名 : 用户定义的合法标识符 (2) 函数的类型 : 函数返回值的类型 若返回值为 int 或char 类型, 函数定义时可省略不写 若函数无返回值, 函数定义时应写上 void 类型 void list(void) { printf(“******\n”); }
(3) 形式参数 ① 书写格式 : 每一个参数都要写上数据类型和参数名 参数之间以逗号分隔, 无参数时一般写上void 声明它为空 ② 作用 : 表示将从主函数中接收哪些类型的信息 例 : int max( int x , int y ) { int z ; z = x > y ? x : y ; return( z ) ; } (4) 函数体: 由变量声明和语句组成 ① 函数体内定义的变量是局部量, 只在执行该函数时存在 ② 函数体可以为空(即存在空函数) void f (void) { }
8.3 函数参数和函数的值 一、形式参数和实在参数 1. 形式参数 : 在定义函数时写在函数名后面的括号内的变量 2. 实在参数: 在调用函数时写在函数名后面的括号内的变量 • 3. 说明 • 程序在编译时不为形参分配存储空间, 只有当函数 • 被调用时, 形参被分配存储空间, 在调用结束后, 形参 • 所占的空间被释放 • (2) 实参可以是常量, 变量或表达式 • (3) 实参和形参的类型应相同或赋值相容 • (4) 实参对形参的数据传递是“值传递”, 即单向传递 • 实参 形参
二、 函数的返回值 1. 函数的返回值通过函数中return语句获得 return语句的作用: 使流程返回主调函数 ; 将函数值送回到调用表达式中 2. 函数类型决定函数返回值的类型 一般函数值的类型和return语句中表达式的类型应一致 如果二者不一致, 则以函数值的类型为准 3. 有的函数中没有return语句, 因为它不需要带回值, 这时 可以将函数类型定义为 void 型 void list(void) { printf(“******\n”); }
4. 一个函数允许有一个或多个return语句, 但每个return 后的表达式类型要相同; 当执行到其中任何一个return 语句时会立即返回主调函数 int fun( int n ) { if ( n >10 ) return( n ) ; else return( 2*n ) ; }
8.4 函数的调用 一、函数调用 1. 一般形式 : 函数名( 实参表列 ) ; 2. 说明 (1) 实参表列可以包含多个实参, 各个实参之间用逗号分隔 (2) 实参与形参的个数应相等, 类型一致, 顺序要一一对应 (3) 调用无参函数时格式为 : 函数名( )注意( )不能省略 (4) BC31中按从左至右的顺序对实参求值 3. 函数调用的方式 (1) 函数语句printf(“hello!”) ; /*标准函数调用*/ (2) 函数表达式 c = 2 * max( a , b ) ; /*自定义函数调用*/ (3) 函数参数 m = max ( c , max ( a , b ) ) ;
4. 函数调用过程 : (1) 形参与实参各自占有一个独立的存储空间 (2) 形参的存储空间在函数被调用时才分配 (3) 函数返回时, 形参占据的临时存储区被撤消 特点 : 函数中对形参变量的操作不会影响到实参 #include <stdio.h> int f (int x , int y) { x = x+2 ; y = y*2 ; return( x+y ) ; } void main ( ) { int a , b , c ; scanf(“%d%d” , &a , &b) ; c = f(a , b) ; printf(“%d\t” , c) ; printf(“%d,%d\n”,a,b); } 假设输入为: 3 5 f 函数 main函数 a 5 x 3 3 10 y b 5 5 c 15 运行结果为:15 3 , 5
二、函数声明 1. 在调用函数前, 一般要对函数事先作出声明 声明有利于编译系统对函数调用的合法性进行检查 2. 声明格式 : 函数类型 函数名 ( 形参表 ); C程序的一般格式: # 命令 函数声明 main函数的定义 其他函数的定义 3. 注意事项: (1)函数声明末尾要加分号 (2) 形参表中可以只写数据类型 如 int f ( int , float ) ; (3)形参的先后次序不能写错 (4) 当被调用的函数定义写在主调函数 之前时, 允许省略函数声明 (5) 建议将程序中用到的函数都在程序的前面加以声明
4. 声明的位置 : (1) 在main 函数中声明 (2) 所有函数进行外部声明 函数声明 函数声明 #include <stdio.h> int f (int x , int y); void main ( ) { int a , b , c ; scanf(“%d%d”, &a, &b); c = f(a , b) ; printf(“%d\n” , c) ; } int f (int x , int y) { x = x+2 ; y = y*2 ; return( x+y ) ; } #include <stdio.h> void main ( ) { int f (int x , int y); int a , b , c ; scanf(“%d%d”, &a, &b) ; c = f(a , b) ; printf(“%d\n” , c) ; } int f (int x , int y) { x = x+2 ; y = y*2 ; return( x+y ) ; } 函数定义 函数定义
例 : 求100-200间的素数 函数定义 int prime( int n ) { int i , k , flag=1 ; k=sqrt(n); for(i=2 ; i<=k ; i++) if(n%i==0) { flag=0 ; break ; } return(flag); } 若m为素数则返回值为 1;否则返回值为0 #include <stdio.h> #include <math.h> int prime( int n ) ; void main( ) { int m , p , num=0 ; for (m=101 ; m<=200 ; m=m+2) {p=prime(m); if (p==1) { printf(“%5d”, m ); num++ ; } } printf(“\n num=%d \n”, num); } 函数声明 函数调用
调用 嵌套 调用 调用 8.5 函数的嵌套调用 C语言规定函数定义都是平行的、独立的, 即函数不能 进行嵌套的定义, 但是函数可以进行嵌套调用. 函数的嵌套调用是指在调用一个函数的过程中调用另 一个函数. main函数 void main( ) { : fun( ) ; : } void fun( void ) { : g( ) ; : } fun函数 g函数
#include <stdio.h> void fa (void) { putchar( ‘a’ ) ; } void fb (void) { fa( ) ; putchar( ‘ t’ ) ; } void main (void) { putchar( ‘c’ ); fb( ) ; } main fb fa 输出a 输出c 调用fa 结束 调用fb 输出t 结束 结束 输出结果: cat
8.6 函数的递归调用 1. 函数递归调用的概念: 在调用一个函数的过程中又直接 或间接地调用该函数自己 2.用递归求解问题的特点 (1)存在某个特定条件,在此条件下可以得到指定的解. (即:递归的终止条件) (2)对任意给定的条件有明确的定义规则,可以产生新的 状态,并将最终导出终止状态. (即:存在导致问题求解的递归方式) 3. 优点 : 程序简洁, 代码紧凑 缺点 : 占用存储空间较多, 时间效率较差
1 n=0,1 n*(n-1) ! n>0 n!= 调用 例: 用递归的方法求n! 递归的终止条件 递归方式 主调函数 返回值24 4!=4*(4-1)! 返回值6 3!=3*(3-1)! 返回值2 2!=2*(2-1)! 返回值1 1!=1
#include <stdio.h> float fac( int n ) ; void main( ) { int m ; float y ; scanf(“%d”, &m ); y=fac(m); /*调用函数fac ()*/ printf(“%d!=%15.0f \n”, m , y ) ; } float fac(int n) { float f ; if ( n<0 ) { printf(“error!”); f=-1; } else if (n==0 || n==1 ) f=1; else f=n*fac( n-1 ) ;/*递归调用自己*/ return(f ) ; } 函数声明 函数定义 递归调用
递归调用过程: 调用fac mn ③ 调用fac mn ② 调用fac mn ① main函数 输入m ③ 因3!=0,1 f=3*fac(3-1) 因2!=0,1 f=2*fac(2-1) 因1==1 f=1 y=fac(m) 输出y ⑥ 返回f ⑥ 返回f ② 返回f ① 结束
8.7 数组作为函数参数 一、数组元素作函数参数(值传递) 其用法与变量作实在参数一样,实参和形参都使用不同 的数组内容,是单向传递 二、数组名作函数参数(地址传递) 实参和形参都使用同一数组内容。 说明: 1. 必须在主调函数和被调函数中分别定义数组 2. 实参数组和形参数组的类型必须一致 3. 数组名作参数实际上是将实参数组的首地址传给形参 数组, 即实参数组和形参数组占用同一片内存单元 4.数组名作参数时,定义形参数组时可以不指定其大小 , 当形参数组发生变化时, 实参数组也随之发生变化
例:求某班成绩的平均分 #include <stdio.h> float average(int s[40]); void main( ) { int i , sc[40] ; float aver ; for(i=0; i<=39 ; i++) scanf(“%d”,&sc[i]); aver=average(sc);/*数组名作参数*/ printf(“aver=%f”, aver); } float average(int s[40]) { int sum , i ; float ave ; sum=0; for(i=0; i<=39 ; i++) sum=sum+s[i]; ave=sum/40; return(ave); } #include <stdio.h> void main( ) { int i , sum , s[40] ; float ave ; for(i=0; i<=39 ; i++) scanf(“%d”,&s[i]); sum=0; for(i=0; i<=39 ; i++) sum=sum+s[i]; ave=sum/40; printf(“ave=%f”, ave); }
数组占用 存储空间 main 调用average scs main average sc[0] sc[1] sc[2] : : : : sc[39] 78 84 90 : : : : 66 s[0] s[1] s[2] : : : : s[39] 输入sc的 40个元素 sum=0 aver=average(sc) 计算sum 输出aver ave=sum/40 结束 返回ave的值
例: 选择排序 #include <stdio.h> void sort ( inta[ ], intn); void main( ) { int b[6] , i ; for ( i=0 ; i<6 ; i++) scanf(“%d”, &b[i] ) ; sort( b , 6 ); /*数组名作参数*/ for ( i=0 ; i<6 ; i++) printf( “%3d”, b[i] ) ; } #include <stdio.h> void main( ) { int a[6] , i , j , k , t; for ( i=0 ; i<6 ; i++) scanf(“%d”, &a[i] ); for ( i=0 ; i<5 ; i++) { k=i ; for ( j=i+1 ; j<6 ; j++) if ( a[k]>a[j] ) k=j ; if ( k!=i ) { t=a[i] ; a[i]=a[k] ; a[k]=t ; } } for ( i=0 ; i<6 ; i++) printf( “%3d”, a[i] ); } voidsort ( int a[ ] , int n) { int i , j , k , t ; for ( i=0 ; i<n-1 ; i++) { k=i ; for ( j=i+1 ; j<n ; j++) if ( a[k]>a[j] ) k=j ; if ( k!=i ) { t=a[i] ; a[i]=a[k] ; a[k]=t ; } } }
8.8 局部变量和全局变量 一、局部变量: 指在一个函数内部定义的变量, 它只在本 函数的范围内有效, 在此函数之外不能使用这些变量 说明: 1. main函数中定义的变量是局部变量, 它们只能在main函数中使用 2. 不同函数中可以使用相同名字的变量,它们互不干扰 3. 形式参数也是局部变量 4. 在复合语句中定义的变量, 它们只在复合语句内有效
#include <stdio.h> void sort ( int a[ ] , int n); void main( ) { int b[6] , i ; for ( i=0 ; i<6 ; i++) scanf(“%d”, &b[i] ) ; sort( b , 6 ); for ( i=0 ; i<6 ; i++) printf( “%3d”, b[i] ) ; } main函数中的局部变量:b和 i 参数a和n也是局部变量 void sort ( int a[ ] , int n) { int i , j , k ; for ( i=0 ; i<n-1 ; i++) { k=i ; for ( j=i+1 ; j<n ; j++) if ( a[k]>a[j] ) k=j ; if ( k!=i ) { int t ; t=a[i] ; a[i]=a[k] ; a[k]=t ; } } } sort函数中的局部变量: i , j, k t 是复合语句中的局部变量, 只能以下在3个赋值语句中使用
全局变量p和 q的有效范围 全局变量数组 s的有效范围 全局变量m和 n的有效范围 二、全局变量: 指在所有函数之外定义的变量( 外部变量) , 它的有效范围从定义变量的位置开始到本源文件结束 #include <stdio.h> int p=1 , q=5 ; float f1( int a ) { float r ; : } int s[10] ; int f2( int b , int c ) ; { int sum ; : } float m , n ; void main( ) { float x , y ; : }
1. 全局变量的使用增加了函数间数据联系的渠道 由于在同一文件中的所有函数都能使用全局变量, 所以 可以利用全局变量从函数中得到一个以上的返回值 例: 求某班成绩的平均分, 最高分和最低分 #include <stdio.h> int max , min ; float average( int s[ ] ); void main( ) { int i , sc[40] ; float aver ; for(i=0; i<=39 ; i++) scanf(“%d”,&sc[i]); aver=average(sc); printf(“aver=%f\n”, aver); printf(“max=%d\n”, max); printf(“min=%d\n”,min); } float average( int s[ ] ) { int sum , i ; float ave ; sum=0; max=min=s[0]; for(i=0; i<=39 ; i++) { sum=sum+s[i]; if (s[i]>max) max=s[i]; else if ( s[i]<min ) min=s[i]; } ave=sum/40; return(ave); }
2. 建议不要过多的使用全局变量 (1) 全局变量在程序的执行过程中一直占用存储单元 (2) 它使函数的通用性降低 (3) 它会降低程序的清晰性 #include <stdio.h> int x=10; void f(void) { int x=1; x=x+1; printf(“x=%d\n”, x ); } void main() { x=x+1; printf(“x=%d\t”, x); f( ); } 3. 在一个源文件中如果局部变量 和全局变量同名, 在局部变量 起作用的范围内, 全局变量 不起作用 输出结果: x=11 x=2
课后作业: P186 8.1、 8.3、 8.5 8.15、8.16
练习8.10 思路:找长度最大的单词,必须记录每一个单词的字母个数,取最大值;并将找到的单词输出。 步骤: 主程序:1、从键盘上输入一行字符,存入一字符数组str中; 2、调用一函数maxstr(),得到字符串中长度最大的单词; 3、将结果输出。 函数maxstr():1、设一个变量len存放最长单词的长度,其初始值为0; 2、从字符串最左边开始,获得每一个单词的长度(即遇到一个空格时,其前面为一个单词,用一个变量记录单词长度),与len比较,若大于,则将其值赋予len,将此单词传送给另一数组str1;循环直到整个字符串执行完为止。 在此最好将str1定义为全局变量,使得在函数maxstr()中得到的值,在主程序中也可以使用。
#include "stdio.h" char str1[10]; maxstr(char a[50] , int n) ; main() { char str[50],danci[10]; int i,dlen; printf("\n input a string:"); gets(str); dlen=strlen(str); maxstr(str,dlen); printf("\nThe max word="); puts(str1); }
maxstr(char a[50],int n) { int i,len,j,m,x; len=0; i=0; while(i<=n) { j=0; while((a[i]!=' ')&&(i<=n)) { j++; i++; } if (j>len) { len=j; x=0;
for(m=i-j;m<=i;m++) { str1[x]=a[m]; x++; } str1[x]='\0'; } i++; } }