高级语言程序设计 课件 第6章 函数_第1页
高级语言程序设计 课件 第6章 函数_第2页
高级语言程序设计 课件 第6章 函数_第3页
高级语言程序设计 课件 第6章 函数_第4页
高级语言程序设计 课件 第6章 函数_第5页
已阅读5页,还剩45页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章函数6.1函数的概念和模块化程序设计函数声明6.2

函数的参数和数据传递方式6.36.4变量的存储类型和作用域6.5函数的嵌套调用和递归调用6.6常用库函数本章内容导读本章主要介绍函数的定义和调用方法,函数之间数据传递方式以及常用的库函数,函数的嵌套调用和递归调用以及模块化程序设计。通过学习本章,读者应掌握以下内容:了解模块化程序设计方法;掌握用户自定义函数的定义和调用方法;掌握函数声明的作用;掌握函数调用时的数据传递方式;了解变量生存期和作用域的概念;了解递归函数的概念和一般设计方法。函数是一段相对独立、功能完整的程序。一个C语言程序是由一个或多个函数组成,每个函数分别对应一个功能模块。特点(1)一个C程序由一个或多个函数组成,其中必须有且只能有一个main函数(称为主函数)。(2)C程序的执行从主函数开始,如果在主函数中调用其他函数,调用后返回到主函数,并在主函数中结束整个程序的运行。(3)主函数可以调用其他函数,但其他函数不能调用主函数。主函数由操作系统调用,其他函数之间可以互相调用。(4)函数之间没有从属关系,互相独立,不能嵌套定义。1、函数的概念

6.1函数的概念和模块化程序设计从函数定义的角度划分库函数(又称标准库函数):由C语言的函数库提供,即C语言自身已经定义好的函数,在包含相应头文件后用户可以直接使用;用户函数(又称自定义函数):是用户根据需要自行定义的完成某一特定功能的一段程序。从函数有无参数的角度划分有参函数:定义函数时有参数的称为有参函数;无参函数:定义函数时无参数的称为无参函数。1、函数的概念

6.1函数的概念和模块化程序设计从函数有无返回值的角度划分有返回值函数:调用后返回一个值;无返回值函数:调用后不返回值。从函数作用范围的角度划分C语言允许将一个源程序分放在不同的程序文件中,采用分块编译、连接生成一个目标程序,其中每个程序文件称为一个“编译单元”。每个编译单元可以包含若干个函数。外部函数:可以被任何编译单元调用的;内部函数:只能在本编译单元中被调用。1、函数的概念

6.1函数的概念和模块化程序设计函数定义的一般形式数据类型符函数名(形式参数表){数据定义语句部分;执行语句部分;}函数首部(函数头)函数体

例:两个数之和的函数。doubleadd(doublex,doubley){

doublez;z=x+y;

returnz;

}函数体:{}中的内容,包括说明语句和执行语句。空函数:函数体为空的函数,例{},便于扩充和细化程序。说明(1)任何函数(包括主函数)都是由函数首部和函数体两部分组成。(2)函数首部末尾不能加分号。(3)“函数名”是一个标识符,在同一个编译单元中函数不能重名。(4)C语言中,所有函数(包括主函数)都是平行的。一个函数的定义,可以放在程序中的任意位置,主函数之前或之后。但是在一个函数的函数体内不能再定义另一个函数,即不允许函数的嵌套定义。2、函数的定义6.1函数的概念和模块化程序设计

无参函数定义格式

数据类型符或void函数名(void){数据定义语句部分;执行语句部分;}

有参函数定义格式

数据类型符或void函数名(形式参数表){定义语句部分;执行语句部分;}2、函数的定义6.1函数的概念和模块化程序设计

无返回值函数定义格式

void函数名(形式参数表或void)

{数据定义语句部分;执行语句部分;

}

有返回值函数定义格式数据类型符函数名(形式参数表或void)

{定义语句部分;执行语句部分;}2、函数的定义6.1函数的概念和模块化程序设计C程序是通过对函数的调用来执行函数体。被调函数应该先定义,后调用。格式

函数名([实际参数表]);调用方式

(1)以函数语句的方式

函数名(实际参数表);(2)以函数表达式的方式

变量=带函数的表达式;(3)以函数实参的方式func1(x,y,z);c=max(a,b);printf("thelargenumberis%f",add(x,y));3、函数的调用6.1函数的概念和模块化程序设计【例6-1】编写一个程序求解从m个元素选n个元素的组合数程序。计算公式:分析:用函数f(x)求x!;cmn=f(m)/f(n)/f(m-n);longf(x)intx;{

longy;

for(y=1;x>0;--x)

y=y*x;

return(y);}#include<stdio.h>int

main(void){

int

m,n;

longcmn,temp;

longf();

printf("Entermandn:");

scanf("%d%d",&m,&n);

cmn=f(m);

temp=f(n);

cmn=cmn/temp;

cmn=cmn/f(m-n);

printf("Thecombination:%ld\n",cmn);

return0;}Entermandn:43Thecombination:4函数的形式参数和实际参数形式参数(简称形参):是在函数定义中设置的,用来接收从主调函数传来的对应实参的数据。实际参数(简称实参):是调用函数时的实际参数,实参可以是常量、变量或表达式,也可以是函数的返回值,无论哪种形式必须有确定的值。注意(1)形参在调用时才被分配内存空间,调用结束后释放。(2)实参可以是常量、变量或表达式,但要求有确定值。(3)实参在数量、类型和顺序上与形参必须一一对应和匹配。如果参数的数量不一致,则会出现编译错误;如果参数的顺序不一致,则传递到被调函数中的数据不合逻辑;如果参数的类型不一致,则按照形参类型对实参进行自动转换,如果是不能进行转换的类型,则出现编译错误。(4)实参向形参的单向传递,“值传递”,即只由实参传给形参,而不能由形参传回给实参。3、函数的调用6.1函数的概念和模块化程序设计返回值类型函数返回值的类型即函数类型,是指返回给主调函数的结果的类型,应根据具体函数的功能确定。如果函数不返回任何值,则函数返回值类型定义为“void”,称为“空类型”。有参函数的返回值,是通过函数中的return语句获得。return语句功能:返回调用函数,并将“返回值表达式”的值带给调用函数。使用方式(1)无返回值的函数return;(2)有返回值的函数return(返回值表达式);或return返回值表达式;4、函数的返回6.1函数的概念和模块化程序设计说明(1)一个函数中可以有多个return语句

(2)若无return语句,则执行到函数体末尾后,并不是不返回一个值,而是返回一个不确定的值。

(3)若无值返回,则函数应定义为void类型。

(4)return语句中表达式的类型与函数类型一致。若不一致,以函数值类型为准。4、函数的返回6.1函数的概念和模块化程序设计(1)暂停执行函数调用所在的语句,转向执行被调函数。(2)为函数的所有形参分配内存,再计算所有实参的值,依次赋予对应的形参。若是无参函数,则不执行这一操作。(3)进入函数体,先执行数据定义语句部分,为函数体中定义的变量、数组等分配内存。(4)执行函数体中的执行语句部分。如果是无返回值的函数,则执行到返回语句;如果返回语句被省略,则执行到函数体的右花括号;如果是有返回值的函数,则执行到返回语句时,计算表达式的值作为函数的返回值。(5)收回分配给函数体中定义的变量、数组、形参等的内存单元。(6)返回到主调函数继续执行。如果函数调用的形式是“语句”,则执行其后面的语句;如果函数调用的形式是“表达式”,则继续执行表达式所在的语句。5、函数的调用过程6.1函数的概念和模块化程序设计C语言中,一个大的程序由许多源程序文件(又称程序模块,通常是一些相关函数的集合)组成,而源程序文件由预编译和许多函数组成。C语言程序源文件(程序模块)结构包含文件,例如#include<stdio.h>宏定义,例如#definePI3.14159条件编译,例如#if…#else…#endif函数声明,例如定义函数的原型全局变量说明,例如函数外定义的变量函数定义源文件包含文件宏定义条件编译函数预说明全局变量说明函数模块定义函数模块定义……大程序6、模块化程序设计方法6.1函数的概念和模块化程序设计在调用函数之前应当对调用的函数进行声明,让编译程序预先了解函数的有关信息。格式[存储类型][数据类型符]函数名(形参类型[形参名1][,形参类型[形参名2],…]);说明(1)函数声明是一条语句,末尾加分号;而函数首部不是语句,末尾不加分号。(2)函数声明与函数定义是不同的。函数定义是编写一段程序,除了指定函数名、返回值类型、形参名、形参类型外,还有函数体;而函数声明只是把函数名、返回值类型、形参名、形参类型等通知编译程序,以便在调用该函数时系统据此对照检查,它没有函数体。例如,int

max(int

x,inty){……}的函数原型是intmax(int,int);6.2函数的声明若主调函数与被调函数不在同一编译单元中,则在定义函数的编译单元中必须将该函数定义为外部函数,同时在主调函数的函数体中或主调函数所在编译单元的开头将被调函数进行声明:extern数据类型符函数名(形式参数表);;若主函数与被调函数在同一编译单元中,则可以不说明其函数原型。同时C语言又规定,若被调函数的函数定义出现在主调函数之前,则在主调函数中可以省略对被调函数的声明。因为在调用之前,编译程序已经知道了被调函数的函数类型、参数个数、类型和顺序等信息。除了上述两种情况,都需要对被调函数进行声明。

6.2函数的声明被调用函数若为系统函数(库函数):除了少数库函数(如scanf()、printf())外,都要求在本文件开头用包含命令包含被调函数的信息。用户函数函数声明的几种形式

数据类型符函数名(形参类型形参名1,形参类型形参名2,……);

数据类型符函数名(形参类型1,形参类型2,……);

数据类型符函数名();intmax(inta,intb);intmax(int,int);intmax();6.2函数的声明说明(1)函数原型告诉编译程序函数返回的数据类型、函数所要接收的参数个数、参数类型和参数顺序,编译程序利用函数原型校验函数调用是否正确。(2)函数原型中可以只说明形参类型和形参个数,而无需说明形参名。例如,对函数intmax(int

x,inty){……}的声明以下两种形式均可:

int

max(int,int);

int

max(int

x,int

y);(3)函数原型、函数定义、函数调用要保持一致。和函数原型不匹配的函数调用会导致语法错误;函数原型和函数定义不一致,也会产生错误。6.2函数的声明说明(4)函数原型可以在主调函数中声明;也可以在所有函数的外部(如文件声明处)进行声明。这种情况下,在该声明之后定义的所有函数均可以调用该函数,而不必再声明。(5)如果程序中没有包含函数原型,则编译程序会用第一次出现的该函数(函数定义或函数原型)来构造函数原型。6.2函数的声明函数之间数据传递方式值传递地址传递返回值全局变量传递前两种方式是利用定义函数时设置的形参和调用函数时给出的实参来传递数据的。

6.3函数的参数和数据传递方式

值传递方式是在形参和实参之间传递数据的一种方式。传递方式传递的是参数值。判断的唯一方法是看函数定义时的形参是不是变量形式如果形参是变量,则是值传递方式。1、值传递方式6.3函数的参数和数据传递方式数组作为函数参数的两种形式

数组元素作为函数实参数组元素只能用作函数实参,其用法与普通变量完全相同,即在发生函数调用时,把数组元素的值传送给形参,实现单向值传送。数组元素作为实参时,只要数组的类型和函数形参的类型一致即可,并不要求函数的形参也是下标变量。换言之,对数组元素的处理是按普通变量对待的。普通变量或下标变量作为函数参数时,形参变量和实参变量由编译程序分配不同的内存单元。在函数调用时进行值传送,把实参变量的值赋予形参变量。

2、数组作为函数参数的数据传递方式6.3函数的参数和数据传递方式数组名作为函数参数(形参和实参)数组名作函数参数时,既可以作形参,也可以作实参。数组名作函数参数时,要求形参和相对应的实参都必须是类型相同的数组(或指向数组的指针变量),都必须有明确的数组说明。如果形参是数组名,则传递方式称为“地址传递方式”

2、数组作为函数参数的数据传递方式6.3函数的参数和数据传递方式当一维数组名做形参时可以指定数组的长度,也可以不指定数组的长度,而只在数组名后面跟一对空的方括号。当多维数组名做实参和形参时,形参数组可以省略第一维的长度说明,但第二维及以上的长度说明不能省略。

不是在形参和实参之间进行数据传递,而是通过函数调用直接返回一个值到主调函数。因此,这种方式通常用于从被调函数向主调函数回传值。注意(1)函数首部中需要有“数据类型符”,说明该函数返回值的数据类型。(2)函数体中需要有语句“return(表达式);”,其中的表达式即是函数的返回值。3、利用返回值的数据传递方式6.3函数的参数和数据传递方式变量存储类型自动型(auto)寄存器型(register)外部型(extern)静态型(static)变量存储方式静态存储方式在编译时由系统分配固定的存储空间,直到程序运行结束后才释放所占用的存储空间。动态存储方式在程序运行时根据需要动态地分配和释放存储空间。自动型和寄存型器变量属于动态存储方式,外部型和静态型变量属于静态存储方式。1、变量的存储类型6.4变量的存储类型和作用域自动型变量

定义格式

[auto]数据类型变量表;

说明

(1)自动变量属于动态存储方式。在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束就释放。在复合语句中定义的自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,否则将引起错误。(2)定义时如果没有初始化,则其值是不确定的。如果初始化,则赋初值操作是在调用时进行的,且每次调用都要重新赋一次初值。(3)由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名。建议:系统不会混淆,并不意味着人也不会混淆,所以尽量少用同名自动型变量!1、变量的存储类型6.4变量的存储类型和作用域静态型变量定义格式

static数据类型变量表;

说明(1)静态内部变量属于静态存储。在程序执行过程中,即使所在函数调用结束也不释放。换言之,在程序执行期间,静态内部变量始终存在,但其它函数是不能引用它们的。(2)定义但不初始化,则自动赋以0(整型和实型)或‘\0’(字符型);且每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值。(3)何时使用静态内部变量:需要保留函数上一次调用结束时的值。变量只被引用而不改变其值。1、变量的存储类型6.4变量的存储类型和作用域寄存器型变量一般情况下,变量的值都是存储在内存。为提高执行效率,C语言允许将局部变量的值存放到寄存器,这种变量称为寄存器变量。

定义格式register数据类型变量表;

说明(1)只有局部变量才能定义为寄存器变量,全局变量不行。(2)对寄存器变量的实际处理,随系统而异。例如,微机上的MSC和TC将寄存器变量实际当作自动变量处理。(3)允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。1、变量的存储类型6.4变量的存储类型和作用域外部型变量定义格式

extern数据类型外部变量表;

说明:外部型变量是专门用于在多个编译单元之间传递数据的。当编译单元A需要使用在编译单元B中定义的变量,则编译单元A需要将该变量声明为外部型变量,以便C编译系统在编译单元A之外的其它编译单元中寻找该变量的定义,而在编译单元B中需要定义该变量的存储类型和数据类型。关键字extern与auto、static和register的用法不同,后三个关键字是在定义变量时加关键字,而extern是对已经定义的全局变量进行声明。注意:函数内的extern变量说明,表示引用本源文件中的外部变量;函数外(通常在文件开头)的extern变量说明,表示引用其它文件中的外部变量。1、变量的存储类型6.4变量的存储类型和作用域变量的生存期从系统为变量分配内存单元(或寄存器)开始到系统收回内存单元(或寄存器)的期间称为“变量的生存期”。在变量的生存期以外使用该变量会导致编译错误。变量的作用域C语言中所有的变量都有其作用域。变量说明的位置不同,其作用域也不同。2、变量的生存期和作用域6.4变量的存储类型和作用域intf1(inta)/*函数f1*/{

int

b,c;

……} /*a、b、c作用域:仅限于函数f1()中*/

intf2(intx)/*函数f2*/{

int

y,z;

……} /*x、y、z作用域:仅限于函数f2()中*/intmain(void){

int

m,n;

……} /*m、n作用域:仅限于函数main()中*/说明(1)主函数中定义的内部变量,也只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的内部变量。因为主函数也是一个函数,与其它函数是平行关系。这一点是与其它语言不同的,应予以注意。(2)形参变量也是内部变量,属于被调用函数;实参变量,则是调用函数的内部变量。(3)允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。(4)在复合语句中也可定义变量,其作用域只在复合语句范围内。2、变量的生存期和作用域6.4变量的存储类型和作用域全局变量

定义:生存期覆盖了定义点到整个程序结束的变量。局部变量定义:生存期只覆盖了某个函数(或复合语句)的变量。对于局部变量,声明存储类型的作用是指定变量的存储位置(静态存储区或动态存储区)和生存期;对于全局变量,声明存储类型的作用是扩展或限制变量的作用域。2、变量的生存期和作用域6.4变量的存储类型和作用域内部变量

定义:在一个函数(或复合语句)内部定义的变量。作用域:该函数(或复合语句)范围内有效,即只在包含变量定义的函数(或复合语句)内部,才能使用该变量,在此函数(或复合语句)之外则不能使用。说明(1)主函数中定义的内部变量,只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的内部变量。因为主函数也是一个函数,与其它函数是平行关系。这一点是与其它高级语言不同。(2)形参变量也是内部变量,仅限于函数内使用。(3)允许在不同函数中使用重名的变量,它们代表不同的对象,分配不同的内存单元,互不干扰,也不会发生混淆。2、变量的生存期和作用域6.4变量的存储类型和作用域说明(4)复合语句中也可定义变量,所定义的变量是内部变量,其作用域只在该复合语句范围内。例如,

if(i>j) {

int

k; k=i;i=j;j=k;k有效 }

2、变量的生存期和作用域6.4变量的存储类型和作用域外部变量定义:在函数外部定义的变量。作用域:从定义位置开始到本文件结束为止。它不属于任何一个函数,可被作用域内的所有函数直接引用。说明(1)外部变量可以加强函数模块之间的数据联系,但又使这些函数依赖这些外部变量,因而使得这些函数的独立性降低。从模块化程序设计的观点来看这是不利的,因此不是非用不可时,不建议使用外部变量。(2)在同一源程序文件中,允许外部变量和内部变量重名。如果外部变量和内部变量重名,则在内部变量的作用域内,外部变量将被屏蔽而不起作用。2、变量的生存期和作用域6.4变量的存储类型和作用域说明(3)外部变量的作用域是从定义点到本文件结束。如果定义点之前的函数需要使用这些外部变量时,需要在函数内对被使用的外部变量进行说明。外部变量说明的一般形式为:extern数据类型外部变量1[,外部变量2……];注意:外部变量的定义和外部变量的说明不同。外部变量的定义,必须在所有的函数之外,且只能定义一次。而外部变量的说明,出现在需要使用该全局变量的函数内,而且可以出现多次。2、变量的生存期和作用域6.4变量的存储类型和作用域静态局部变量和静态外部变量同属静态存储方式,区别在于:(1)定义的位置不同。静态局部变量在函数内定义,静态外部变量在函数外定义。(2)作用域不同。静态局部变量属于内部变量,其作用域仅限于定义它的函数内;虽然生存期为整个源程序,但其它函数是不能使用它的。静态外部变量在函数外定义,其作用域为定义它的源文件内;生存期为整个源程序,但其它源文件中的函数也是不能使用它的。(3)初始化处理不同。静态局部变量,仅在第1次调用它所在的函数时被初始化,当再次调用定义它的函数时,不再初始化,而是保留上1次调用结束时的值。而静态外部变量是在函数外定义的,不存在静态内部变量的“重复”初始化问题,其当前值由最近1次给它赋值的操作决定。

2、变量的生存期和作用域6.4变量的存储类型和作用域务必牢记:把局部变量改变为静态内部变量后,改变了它的存储方式,即改变了它的生存期。把外部变量改变为静态外部变量后,改变了它的作用域,限制了它的使用范围。因此,关键字“static”在不同的地方所起的作用是不同的。2、变量的生存期和作用域6.4变量的存储类型和作用域不是在形参和实参之间传递数据,而是利用在主调函数和被调函数中都有效的全局变量,在主调函数和被调函数之间共享数据。如前所述,全局变量是生存期覆盖了定义点到整个程序结束的变量。具体地,全局变量有两种,一是在任何函数之外定义的全局变量,其作用域覆盖了定义点到整个程序结束之间的所有函数,这种全局变量叫做“外部变量”;二是在函数体内部定义为static型的变量,该变量在从函数返回后,仍保留所分配的内存(活着),但是不能使用,其作用域仍是该函数体内。这种全局变量叫做“内部变量”。因此,在函数之间利用全局变量传递数据,只能使用“外部变量”。3、利用全局变量的数据传递方式6.4变量的存储类型和作用域递归函数:又称自调用函数,简洁但不一定高效。三个条件:(1)递归问题的规律;

(2)通过转化解决问题;

(3)有终止递归的条件。【例6-2】阶乘的递归函数。

分析:f(n)=n*f(n-1);f(1)=1;intf(n)intn;{if(n==1)return(1);elsereturn(n*f(n-1));}intmain(void){intx=4;printf("n!=%d\n",f(x));return0;}n!=246.5函数的嵌套调用和递归调用在执行被调用函数时,被调用函数又调用了其它函数。这与其它语言的子程序嵌套调用的情形类似。main()函数①调用f1()函数:结

束f1()函数调用f2()函数:后续语句:后续语句:返

回f2()函数返

回②③④⑤⑥⑦⑧⑨1、函数的嵌套调用6.5函数的嵌套调用和递归调用【例6-3】计算s=1k+2k+3k+……+Nk

。/*功能:函数的嵌套调用*/#include<stdio.h>#defineK4#defineN5longf1(int

n,intk) /*计算n的k次方*/{longpower=n;

inti;for(i=1;i<k;i++)power*=n;returnpower;}longf2(int

n,intk) /*计算1到n的k次方之累加和*/{longsum=0;

inti;for(i=1;i<=n;i++)sum+=f1(i,k);returnsum;}intmain(void){printf("Sumof%dpowersofintegersfrom1to%d=",K,N);

printf("%d\n",f2(N,K));

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论