《计算机C语言教程第6章函数》由会员分享,可在线阅读,更多相关《计算机C语言教程第6章函数(58页珍藏版)》请在金锄头文库上搜索。
1、C C语言程序设计语言程序设计第六章第六章 函数函数第六章第六章 函数函数6.1 6.1 概述概述 一个函数是根据进去的信息(输入)和产生的东西(输出结果)所定义的一个黑盒。在 C 语言函数中: 我们用参数把值传送进函数: 我们用 RETURN 把一个值返回调用函数。 2) 除main函数外,其它函数可相互调用main ( )abcdxz3)函数不可嵌套定义,具有全局性、平行性,4)函数分为有参与无参函数5)程序从main开始执行,最后又回到main函数结束。1) 除main外, 其它为系统函数、自编函数,系统函数:由系统提供,用户可调用。自编函数:由用户按语法规则编写。C程序由一个main和
2、任意个函数组成。1. 无参函数定义形式类型标识符类型标识符 函数名函数名( ) 说明部分说明部分 语句语句 类型标识符: 表示返回值类型。一、函数定义一、函数定义6.2 6.2 函数的定义与调用函数的定义与调用例6.1 利用函数实现信息打印#includeVoid print_space()printf(“n”);Void print_message()printf(“n Welcome you to use Clanguage !”);print_spoace();main()print_message();print_space(); 调用方式函数名( ) ;若有返回值可出现在表达式中无返
3、值可单独出现例 通过调用print_space ( ), print_ message( )而显示: Welcome you to use C language ! 就是无参函数类型标识符类型标识符 函数名函数名(形参表列形参表列) 形参说明说明部分形参说明说明部分 语句语句 2. 有参函数 定义形式例: 求二数之最大值 int max (int x, int y) int z; z=xy? x:y; return (z); 注意:注意:出现return, 语句,返回值一般与函数类型一致。有参函数的构造演示:一一 函数调用的一般形式函数调用的一般形式函数名函数名(实参表列实参表列); 1)如果
4、是调用无参函数,则“实参表列”可以没有,但括弧不能省略。 2)如果实参表列包含多个实参,则各参数间用逗号隔开。实参与形参的个数应相等,类型应一致。实参与形参按顺序对应,一一传递数据。 3)实参传递给形参时,实参的计算有的系统自左至右,有的自右至左。二、函数调用二、函数调用二二 函数调用的方式函数调用的方式 按函数在程序中出现的位置来分,可以有以下三种函数调用方式:1、函数语句、函数语句把函数调用作为一个语句。如例中的printstar();这时不要求函数带回值,只要求函数完成一定的操作。2、函数表达式、函数表达式函数出现在一个表达式中,这种表达式称为函数表达式。这时要求函数带回一个确定的值以参
5、加表达式的运算。例:例:c=2*max(a,b);函数max是表达式的一部分,它的值乘以2再赋给c。3、函数参数、函数参数 函数调用作为一个函数的实参。例:例:m=max(a,max(b,c); 其中max(b,c)是一次函数调用,它的值作为max另一次调用的实参。 m的值是a、b、c三者最大的。又如:又如:printf(“%d”,max(a,b);也是把max(a,b)作为printf函数的一个参数。三三 对被调用函数的声明和函数原型对被调用函数的声明和函数原型在一个函数中调用另一个函数,需要具备哪些条件呢? 1)首先被调函数必须是已存在的函数(是库函数或用户自己定义的函数)。 2)如果使用
6、库函数,一般还应该在本文件开头用 #include 命令将调用库函数时所需用到的信息“包含”到本文件中来。 3) 调用函数应对被调用函数的返回值类型作出说明: (函数名相当于一变量,但应有所区别)类型符 函数名( );它不同于函数的定义(功能定义) 例8.5 : 求二实数之和 main ( ) float add( float x,float y); float a, b, c; scanf(%f, %f,&a, &b); c=add(a, b); printf (sum= %f;c); float add( float x, float y); float z; z=x+y; return
7、z; 注意注意:以下几种情况可省略对被调函数的说明: 1)当返回值为整型、字符型。 2) 在调用之前定义函数。 3) 在整个文件的开头定义函数。函数原型函数原型在c语言中,函数声明称为函数原型函数原型(function prototype)函数原型的一般形式:(1)函数类型)函数类型 函数名(参数类型函数名(参数类型1,参数类型,参数类型2,)(2)函数类型)函数类型 函数名(参数类型函数名(参数类型1,参数名,参数名1,参数类型,参数类型2,参数名,参数名2,) 应当保证函数原型与函数首部写法上的一致,即函数类型、函数名、参数个数、参数类型和参数顺序必须相同。函数调用时函数名、实参类型必须与
8、函数原型中的形参类型赋值兼容。说明:说明: 1)以前的C版本函数声明方式不是采用函数原型,而只声明函数名和函数类型。例如在例中,也可写成: float add( );新版本也兼容这种写法,但不提倡这种用法。 2)如果在函数调用之前,没有对函数作声明,则编译系统会把第一次遇到的该函数形式(函数定义或函数调用)作为函数的声明,并将函数类型默认为int型。 3)如果被调用函数的定义出现在主调函数之前,可以不加声明。 4)如果已在所有函数定义之前,在函数外部已做了函数声明,则在各个主调函数中不必对所调用的函数再作声明。6.3 6.3 函数参数函数参数 当调用一个带形式参数的函数时, 我们用到实际参数。
9、实际参数是在调用时赋给相应的形式参数的特殊的值。调用函数调用函数实际参数实际参数被调用函数被调用函数 形式参数形式参数一一 形参与实参形参与实参调用时调用时: 实参值单向传递形参。 函数被调用时,临时分配单元给形参,调用完毕, 这些单元被释放。实参实参: 出现在调用函数中, 形参: 出现被调用函数中。注注: 实参可为表达式,其值传递。 实参、形参类型一致。 可在形参表列中对形参说明。例例 输入两个数,输出其中较大的数。#include int max(int x,int y) int t; if(xy) t=x; else t=y; return t;void main() int a,b,m
10、; int max(int,int);/*对函数max的声明*/ scanf(“%d,%d”,&a,&b); m=max(a,b);/*调用函数max(),a,b已有具体的值*/ printf(“max=%d”,m);例如运行时输入:10,5输出为:10 实参a和形参x,实参b和形参y之间值的传递如下图 :二二 函数返回值函数返回值 1)通过return语句将返回值传给函数名,可有多个return.变量等return (表达式);通常,希望通过函数调用使主调函数得到一个确定的值。由函数名只能得到一个返回值。说明:说明: 一个函数中可以有一个以上的return语句,执行到哪个return语句,哪
11、个语句起作用。 2) 返回值类型为函数类型。 一般return中的返回值类型应与函数定义时的类型一致, 不一致时,以函数定义类型为准。 凡不加类型说明的函数,一律按整型处理。return语句后面的括弧也可以不要,如:return z;与“return (z);”等价。return 后面的值可以是一个表达式。如:Max(int x,int y) return(xy?x:y);例 设求最大公约数的程序如下:#include int divisor(int a,int b)int r;do r=a%b; a=b;/*形式参数的值在函数被改变形式参数的值在函数被改变*/ b=r; while(r!=0
12、);return a;void main()int a,b,d;scanf(“%d,%d”,&a,&b);if(ab) /*把较大的数传给函数的第一个参数把较大的数传给函数的第一个参数*/ d=divisor(a,b); /*实参与形参同名实参与形参同名*/else d=divisor(b,a);printf(“a=%d,b=%dn”,a,b); /*变量变量a和和b的值不会被函数改变的值不会被函数改变*/printf(“d=%d”,d);注意:注意:函数的按值传递和按地址传递的区别。 函数divisor中的形式参数的a得到实参a的值,而形参b得到实参b的值。divisor中a和b值的改变并不
13、影响主函数中的a和b。所以输出结果为: a=21,b=15 d3 如果程序运行时输入的是:15,2l 函数divisor中的形式参数的a得到实参b的值,而形参b得到实参a的值。则输出结果为: a=15,b21 d3 C语言不能嵌套定义,但可以嵌套调用函数。也就是说,在调用一个函数的过程中,又调用另一个函数。 6.4 6.4 函数的嵌套与递归调用函数的嵌套与递归调用 请看下图:一、函数嵌套调用f1( )调用f2函数 f2( ) main 调用f1函数 结束 上图是两层嵌套(连main函数共3层函数),其执行过程是: (1)执行main函数的开头部分; (2)遇函数调用f1的操作语句,流程转去f1
14、函数; (3)执行f1函数的开头部分; (4)遇调用f2函数的操作语句,流程转去函数f2; (5)执行f2函数,如果再无其他嵌套的函数,则完成f2函数的全部操作; (6)返回调用f2函数处,即返回f1函数; (7)继续执行f1函数中尚未执行的部分,直到f1函数结束; (8)返回main函数中调用f1函数处; (9)继续执行main函数的剩余部分直到结束。例:计算s=13+23+33+103 方法如下:long f2(int n,int k) /*计算n的k次方*/ long power=n; int i; for(i=1;ik;i+) power *= n; return power; lon
15、g f1(int n,int k) /*计算1到n的k次方之累加和*/ long sum=0; int i; for(i=1;i1)即: 条件成立,调用递归,否则结束。一个最常用的例子: 求n!1. 从数学上定义从数学上定义 2、程序:、程序: float fac(n) int n; float f; if (n%cn , getone, putone); void hanoi (n, one, two, three) /*将将n个盘从个盘从one借助借助two,移动移动three*/char one, two, three; int n; if (n= =1) move (one, thre
16、e); else hanoi (n1, one, three, two); move (one, three); hanoi (n1, two, one, three); main ( ) int m; printf ( input the number of disdes :); scanf( %d ,&m); printf( The step to moving %3d disdes:n , m); hanoi (m, A, B, C); 运行情况如下: input the number of disdes:3 The step to moving 3 diskes: A C A B C
17、B A C B A B C A C两个函数: move (getone, putone) 表示从getone 塔移一个盘子至putone塔 hanoi(n, one, two, three) 表示n个盘子从one塔借助于two塔(空)移至three塔。 调用时塔用字符常量A , B , C 表示。让我们看一看, 当盘数是 3 时, towers() 的执行情况。6.5 6.5 变量作用域与存储方式变量作用域与存储方式6.5.1 变量的作用域变量的作用域变量有效的范围称变量的作用域。 C语言中所有的变量都有自己的作用域。变量说明的方式不同,其作用域也不同。C语言中的变量,按作用域范围可分为两种,
18、即局部变量和全局变量。一、局部变量 凡在函数(含main 函数)内部定义的变量称为局部变量。局部性: 局部变量仅在函数内部有效。 其作用域仅限于函数内,在函数内才能引用,即可以对它赋值或取值。在作用域以外,使用它们是非法的。 2. 形参为局部变量。 3. 在复合语句中可定义仅复合语句中有效的临时变量。1. 不同的函数可具有同名的变量,它们占不同的内存单元,互不影响。二、全局变量例: int p=1, q=5; float f1(a) int a; int b, c; char c1, c2; p,q的作用范围c1, c2的作用范围 一个源文件中,在所有函数之外定义的变量为全局变量。有效性: 自
19、定义位置开始至文件结尾全部有效。 char f2(x,y); int c, y; int i, j; main ( ) 1. 全局变量所作用到的函数,相当于这些函数的公共变量。于是,当一个函数对其值进行改变后,另一个函数使用该变量的值亦相应改变。好处: 函数之间值传递。2. 不要随意使用全局变量。一是始终占据内存单元;二是由于函数依赖于外部定义的变量,减少了通用性。3. 不在作用域内函数。若使用全局(外)变量,需在函数体内加上extern保留字。4. 全局和局部变量同名时,局部变量有效。 float f1 (x) int x; extern int a, b; int a0; b= 1 mai
20、n ( ) a, b作用域一、变量的存储类别程序区静态存储区动态存储区数据,变量存放内存分配C语言特有的方式。表达了一个变量存在的时间。6.5.2 变量的存储方式变量的存储方式静态存储变量: 存放于静态存储区,在程序整个运行过程中,始终占据固定的内存单元。动态存储变量: 存放于动态存储区,根据程序的运行状态(如:函数调用)而临时分配的单元,且单元并不固定。以上为两大类,又分为四种具体形式1.自动型变量(auto)2. 静态(static)变量3. 寄存器型变量4. 外部(extern)变量 前面学习的局部、全局变量均以上述方式中的一种形式存储。二、局部变量 局部变量既可以静态方式 , 又可以动
21、态方式存储。动态方式: auto int a, b; 则: a, b为自动型,存入动态区。在该函数被调用时才分配单元,函数调用结束时释放。 auto一般省略。以前用到的变量均为auto型,除static外。现在, 我们看一个例子: 若定义时赋初值,则程序运行中仅在第一次调用时赋初值,第二次调用不再赋初值,而是使用上一次调用的值。则: a, b存入静态区。 函数中的a, b始终占据固定存储单元。 静态方式: static int a, b;现在, 我们看一个例子: int fac (n) int n; static int f=1; f=fn; return(f); main ( ) int i
22、; for (i=1; i=5; i+) printf (%d!=%dn, i, fac(i); 例:求n!运行结果为: 1!1 2!2 3!6 4!24 5!120 每一次调用fac(i),打印一个i!,同时保留这个i!的值以便下次再乘(i+1)。 若不赋初值,则系统置初值0,而动态变量不赋初值则值不确定。 当动态局部变量在一个函数中反复被用达到数百次以上,为了提高效率,可将其存入寄存器中(有限个),不存入内存的动态区中。说明方式 register int i, j=1; 不可多, 一般13个 必要时使用。三、全局变量 在函数外部中定义,它们一定存放在静态存贮区中。 全局变量即可被本文件中各
23、函数用,亦可被其它源文件中的函数引用。1. 只被本文件中的函数引用 全局变量本身一定是存放在静态区的。但若加上 staic. 即:static int a, b; float f1(x)int 则表明a,b只被本文件中各函数引用,即使与其它文件中的全局变量同名,也互不影响。2. 可被其它文件中的函数引用 int a; main( ) extern int a; fac(x) int x z=a 文件文件用到f1.c 中的a中的extern在函数外说明,在函数内说明已叙述过。存储类别总结 见表函数内函数外作用域存在性作用域 存在性 auto register static 局部 static 局
24、部 本文件 不加 static 全局(外部)6.6 6.6 内部函数、外部函数和系统函数内部函数、外部函数和系统函数 函数本身在一个文件中为全局的。即一个文件中定义的函数可被该文件的所有其它函数引用。但函数能否被其它文件中的函数所引用呢?为此分为: 内部函数、外部函数一、内部函数只能在本文件中调用static 类型标识符类型标识符 函数名函数名(形参表形参表)例: static int max (a, b) int a, b; 则该函数max只能被本文件中的其它函数引用,而不能被其它文件中的函数引用。既可被本文件中的函数调用,也可被其它文件中的函数调用。 extern 类型标识符类型标识符 函
25、数名函数名(形参表形参表) 一般系统在调用外部函数的函数中用extern说明外部函数。二、外部函数extern 可省略例: 有一个字符串,内有若干个字符,程序将字符串中该字符删除去。用外部函数实现。 file1.c(文件文件1)main ( ) extern enter_string ( ), delete_string( ), print_string( ); /* 说明本文件要用到其它文件中的函数*/ char c; static char str80; enter_string (str); scanf (%c, &c); delete_string (str, c); print_st
26、ring (str); file2.c (文件文件2)#include stdio.h extern enter_string (str) /*定义外部函数enter_string*/char str80; gets (str); /* 读入字符串str */ file3.c (文件文件3) extern delete_string (str, ch) /* 定义外部函数delete_string */ char str , ch; int i, j; for (i=j=0; stri!= 0 ; i+) if (stri!=ch) strj+=stri; stri= 0 ; file4.c
27、(文件文件4)extern print_string (str) /* 定义外部函数print_string */char str ; printf(%s, str); 运行情况如下: abcdefgc (输入str) c (输入要删去的字符) abdefg (输出已删去指定字符的字符串) 连接 link file1+file2+file3+file4主函数或者在 main ( )中 #include file2.c #include file3.c #include file4.c编译时,将上述三个文件中的函数插在前面。编译: 分别编译三、系统函数对系统函数的一般调用形式为: 函数名函数名(参数表参数表)C语言中对系统函数的调用可以出现在表达式中,如: if(iexp(n) i=2;其中exp为求en的系统函数;也可以出现在函数语句中,完成某种操作,如: printf(“hello! n “); 常用的系统函数包括数学函数、字符函数、字符串函数、输入输出函数、动态存储分配函数等,具体参见函数库附录。 具体各系统函数的功能、参数个数和类型、函数值的类型以及有关的标准头文件都在附录中有具体说明,只需根据需要选用合适的系统函数正确进行调用,即可得到所需计算结果或完成指定的操作。调用时注意实参变量与形参变量的类型匹配,个数相同,并注意函数返回值类型。