
《C语言程序设计》第8章 函数.pdf
48页第8章函数C语言是通过函数来实现模块化程序设计的所以较大的C语言应用程序,往往是由多个函数组成的,每个函数分别对应各自的功能 模块 8.1 函数的定义与调用 8.2 函数的嵌套调用与递归调用 8.3 数组作为函数参数 8.4 内部变量与外部变量 8.5 内部函数与外部函数 8.6 变量的动态存储与静态存储[Return]8.1 函数的定义与调用8 . 1 . 1 函数的定义 8 . 1 . 2 函数的返回值与函数类型 8 . 1 . 3 对被调用函数的说明和函数原型 8 . 1 . 4 函数的调用 8 . 1 . 5 函数的形参与实参[Return]8.1 .1 函数的定义1.任何函数(包括主函数main())都是由函数说明 和函数体两部分组成根据函数是否需要参数,可将函 数分为无参函数和有参函数两种1)无参函数的一般形式函数类型 函数名( void ){ 说明语句部分;可执行语句部分;}如果不需要参数,可以用“ void” 表示,主函数main() 例外2)有参函数的一般形式函数类型 函数名( 数据类型 参数[,数据类型 参数2…… ] ){ 说明语句部分;可执行语句部分;}有参函数比无参函数多了一个参数表。
调用有参 函数时,调用函数将赋予这些参数实际的值为了与调用函数提供的实际参数区别开,将函数 定义中的参数表称为形式参数表,简称形参表[案例8.1] 定义一个函数,用于求两个数中的大数 /*功能:定义一个求较大数的函数并在主函数中调用*/ int max(int n1, int n2)/*定义一个函数max()*/ { return (n1>n2?n1:n2); } main() { int max(int n1, int n2);/*函数说明*/ int num1,num2; printf(“input two numbers:\n“); scanf(“%d%d“, /*使程序暂停,按任一键继续*/ } [程序演示]2.说明(1)函数定义不允许嵌套在C语言中,所有函数(包括主函数main())都是平行的一个 函数的定义,可以放在程序中的任意位置,主函数main()之前或之 后但在一个函数的函数体内,不能再定义另一个函数,即不能嵌 套定义2)空函数──既无参数、函数体又为空的函数其一般形式 为:[函数类型] 函数名(void){ }(3)在老版本C语言中,参数类型说明允许放在函数说明部分 的第2行单独指定。
[Return]8.1.2 函数的返回值与函数类型C语言的函数兼有其它语言中的函数和过程两种功能,从这个 角度看,又可把函数分为有返回值函数和无返回值函数两种 1.函数返回值与return语句 有参函数的返回值,是通过函数中的return语句来获得的 (1)return语句的一般格式:return ( 返回值表达 式 ); (2)return语句的功能:返回调用函数,并将“ 返回 值表达式” 的值带给调用函数 注意:调用函数中无return语句,并不是不返回一个值,而是一 个不确定的值为了明确表示不返回值,可以用“ void” 定义成“ 无 (空)类型” 2.函数类型在定义函数时,对函数类型的说明,应与return 语句中、返回值表达式的类型一致如果不一致,则以函数类型为准如果缺省函数 类型,则系统一律按整型处理良好的程序设计习惯:为了使程序具有良好的可 读性并减少出错,凡不要求返回值的函数都应定义为 空类型;即使函数类型为整型,也不使用系统的缺省 处理[Return]8.1.3 对被调用函数的说明和函数原型在ANSI C新标准中,采用函数原型方式,对被调用函数进行说明,其一般格式如下:函数类型 函数名(数据类型[ 参数名][, 数据类型[ 参数名2]… ]);C语言同时又规定,在以下2种情况下,可以省去对被调用函数的说明:(1)当被调用函数的函数定义出现在调用函数之前时。
因为在调用之前,编译系统已经知道了被调用函数的函数类型、参数个数、 类型和顺序2)如果在所有函数定义之前,在函数外部(例如文件开始处)预先对各个函数进行了说明,则在调用函数中可缺省对被调用函数的 说明[Return]8.1.4 函数的调用在程序中,是通过对函数的调用来执行函数体的,其过程与其它 语言的子程序调用相似C语言中,函数调用的一般形式为: 函数名([实际参数表])切记:实参的个数、类型和顺序,应该与被调用函数所要求的参 数个数、类型和顺序一致,才能正确地进行数据传递在C语言中,可以用以下几种方式调用函数:(1)函数表达式函数作为表达式的一项,出现在表达式中, 以函数返回值参与表达式的运算这种方式要求函数是有返回值的2)函数语句C语言中的函数可以只进行某些操作而不返回 函数值,这时的函数调用可作为一条独立的语句3)函数实参函数作为另一个函数调用的实际参数出现这 种情况是把该函数的返回值作为实参进行传送,因此要求该函数必 须是有返回值的说明:(1)调用函数时,函数名称必须与具有该功能的自 定义函数名称完全一致2)实参在类型上按顺序与形参,必须一一对应和 匹配如果类型不匹配,C编译程序将按赋值兼容的规则 进行转换。
如果实参和形参的类型不赋值兼容,通常并 不给出出错信息,且程序仍然继续执行,只是得不到正 确的结果3)如果实参表中包括多个参数,对实参的求值顺 序随系统而异有的系统按自左向右顺序求实参的值, 有的系统则相反Turbo C和MS C是按自右向左的顺序进 行的 (如何测试)[Return]8.1.5 函数的形参与实参函数的参数分为形参和实参两种,作用是实 现数据传送形参出现在函数定义中,只能在该函数体内 使用发生函数调用时,调用函数把实参的值复 制1份,传送给被调用函数的形参,从而实现调 用函数向被调用函数的数据传送[案例8.3] 实参对形参的数据传递/*实参对形参的数据传递/void main() { void s(int n); /*说明函数*/ int n=100; /*定义实参n,并初始化*/ s(n); /*调用函数*/ printf(“n_s=%d\n“,n); /*输出调用后实参的值,便于进行比较*/ getch(); }void s(int n) { int i; printf(“n_x=%d\n“,n); /*输出改变前形参的值*/ for(i=n- 1; i>=1; i- - ) n=n+i; /*改变形参的值*/ printf(“n_x=%d\n“,n); /*输出改变后形参的值*/ } [程序演示]说明:(1)实参可以是常量、变量、表达式、函数等。
无论实参是何 种类型的量,在进行函数调用时,它们都必须具有确定的值,以便 把这些值传送给形参因此,应预先用赋值、输入等办法,使实参获得确定的值2)形参变量只有在被调用时,才分配内存单元;调用结束时, 即刻释放所分配的内存单元因此,形参只有在该函数内有效调用结束,返回调用函数后, 则不能再使用该形参变量3)实参对形参的数据传送是单向的,即只能把实参的值传送 给形参,而不能把形参的值反向地传送给实参4)实参和形参占用不同的内存单元,即使同名也互不影响[Return]8.2 函数的嵌套调用和递归调用8.2.1 函数的嵌套调用函数的嵌套调用是指,在执行被调用函数时,被调用函数又调 用了其它函数这与其它语言的子程序嵌套调用的情形是类似的, 其关系可表示如下图所示[案例8.4] 计算s=1k+2k+3k+… … +N k /*功能:函数的嵌套调用*/ #define K 4 #define N 5 long f1(int n,int k)/*计算n的k次方*/ { long power=n; int i; for(i=1;i1) f=power(n- 1)*n; else f=1; return(f); }main() { int n; long y; printf(“input a inteager number:\n“); scanf(“%d“, y=power(n); printf(“%d!=%ld\n“,n,y); getch(); }[程序演示][Return]8.3 数组作为函数参数数组用作函数参数有两种形式:一种是把数组元素 作为实参使用;另一种是把数组名作为函数的形参和实 参使用。
8.3.1 数组元素作为函数参数8.3.2 数组名作为函数的形参和实参[Return]8.3.1 数组元素作为函数参数数组元素又称下标变量,它与普通变量并无区别数 组元素只能用作函数实参,其用法与普通变量完全相同: 在发生函数调用时,把数组元素的值传送给形参,实现单 向值传送 [案例8.6] 写一函数,统计字符串中字母的个数 /*功能:数组元素作为函数实参*/ int isalp(char c) { if (c>='a' else return(0); }main() { int i,num=0; char str[255]; printf(“Input a string: “); gets(str); for(i=0;str[i]!='\0';i++) if (isalp(str[i])) num++; puts(str); printf(“num=%d\n“,num); getch(); }[程序演示]说明:(1)用数组元素作实参时,只要数组类型和函数的形参类型一致即可,并不要求函数的形参也是下标变量 换句话说,对数组元素的处理是按普通变量对待的。
2)在普通变量或下标变量作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元 在函数调用时发生的值传送,是把实参变量的值赋予形 参变量[Return]8.3.2 数组名作为函数的形参和实参数组名作函数参数时,既可以作形参,也可以作实参 数组名作函数参数时,要求形参和相对应的实参都必 须是类型相同的数组(或指向数组的指针变量),都必 须有明确的数组说明 [案例8.7] 已知某个学生5门课程的成绩,求平均成绩 float aver(float a[ ]) /*求平均值函数*/ { int i; float av,s=a[0]; for(i=1;i<5;i++) s += a[i]; av=s/5; return av; }void main() { float sco[5],av; int i; printf(“\ninput 5 scores:\n“); for(i=0;i<5;i++) scanf(“%f“, }[程序演示]说明:(1)用数组名作函数参数,应该在调用函数和被调 用函数中分别定义数组,且数据类型必须一致,否则结 果将出错。
例如,在本案例中,形参数组为a[],实参数 组为sco[],它们的数据类型相同2)C编译系统对形参数组大小不作检查,所以形 参数组可以不指定大小例如,本案例中的形参数组a[]如果指定形参数组的大小,则实参数组的大小必须 大于等于形参数组,否则因形参数组的部分元素没有确 定值而导致计算结果错误[Return]8.4 内部变量与外部变量C语言中所有的变量都有自己的作用域变量 说明的位置不同,其作用域也不同,据此将C语言中 的变量分为内部变量和外部变量8.4.1 内部变量8.4.2 外部变量[Return]8.4.1 内部变量在一个函数内部说明的变量是内部变量,它只在该函数范围内有效也就是说,只有在包含变量说明的函数内部。
