第06章-函数与变量作用域_第1页
第06章-函数与变量作用域_第2页
第06章-函数与变量作用域_第3页
第06章-函数与变量作用域_第4页
第06章-函数与变量作用域_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

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

文档简介

第7章函数与变量作用域C语言是通过函数来实现模块化程序设计的。教学目的:掌握函数的定义与调用,变量的作用域;了解函数的嵌套与递归调用,内部、外部函数特点,以及变量的存储特性。11/14/20231教学内容:7.1*函数的定义与调用7.2函数的嵌套调用与递归调用7.3内部函数与外部函数7.4*内部变量与外部变量7.5变量的存储特性本章要点本章作业与上机实践11/14/202327.1*

函数定义与函数调用7.1.1函数定义任何函数都是由函数说明和函数体两部分组成。1.分类根据函数有无参数,将函数分为无参函数和有参函数。11/14/20233(1)无参函数[函数类型]函数名(void){说明语句部分;可执行语句部分;

}(2)有参函数[函数类型]函数名(数据类型参数[,数据类型参数2…]){说明语句部分;可执行语句部分;

}形参表。调用有参函数时,由调用函数为形参提供实际值,简称为实参。在新标准中,函数不可缺省参数表;用“void”表示不需要参数。11/14/202342.函数的返回值与函数类型C语言的函数,还可分为有返回值函数和无返回值函数两种。(1)有返回值函数与return语句①一般格式:

return(返回值表达式);②功能:返回调用函数,并将“返回值表达式”的值带给调用函数。注意:函数中无return语句,返回1个不确定的值。可用“void”定义成“无(空)类型”,明确表示不返回值。括号可以缺省11/14/20235(2)函数类型①函数类型应与return语句中“返回值表达式”的类型一致。如果不一致,则以函数类型为准。②如果缺省函数类型,则系统一律按int型处理。良好的程序设计习惯:为了使程序具有良好的可读性并减少出错,将无返回值函数定义为空类型void;同时,也不使用系统对函数类型的缺省处理。11/14/20236[案例7.1]定义一个求两个整数中极大值的max()函数。

/*功能:求2个整数中的较大数*//*形参:2个,整型*//*返回值:2个整数中的较大数*/intmax(intn1,intn2) /*函数定义*/{return(n1>n2?n1:n2);

}/**/voidmain(void){int

max(intn1,intn2); /*对被调用函数进行说明*/

intnum1,num2;

printf("inputtwonumbers:");

scanf("%d%d",&num1,&num2);

printf("max=%d\n",max(num1,num2));

}对函数的注释11/14/202373、说明(1)函数定义不允许嵌套。一个函数的定义,可以放在程序中的任意位置,但不能在另一个函数的函数体内,即不能嵌套定义。例如:main(){……

intmax(……){……}}(2)空函数──函数体为空的无参函数:[函数类型]函数名(void){}11/14/202387.1.2函数调用与返回1、对被调用函数的说明和函数原型(1)函数说明的一般格式

在新标准中,采用函数原型方式,对被调用函数进行说明:

函数类型函数名(形参表);11/14/20239(2)函数说明的两种方式①谁调用谁说明:函数说明语句放在调用函数的函数体中。例如,在[案例7.1]主函数main()中:voidmain(void){intmax(intn1,intn2);

……}对被调用函数进行说明11/14/202310②预先统一说明——函数说明通常放在所有函数定义体之前。在这种方式下,所有调用函数都无需再对自定义函数进行说明。例如,在[案例7.1]中,可以将对max()函数的说明放在程序文件开始处:voidmain(void){

int

max(intn1,intn2);……}11/14/202311显然,对于被多个函数调用的自定义函数而言,采用预先统一说明方式进行说明,可以有效地减少函数说明次数。

注意:如果被调用函数的定义体,出现在调用函数之前,可以缺省说明。11/14/2023122、函数调用

函数名([实参表])

例如,在[案例7.1]的主函数中:

printf(……,max(num1,num2)

);注意:调用有参函数,必须提供实参(常量/变量/表达式/函数)。调用时,实参必须具有确定的值,且与形参个数相等、类型匹配。11/14/202313(1)调用方式①语句方式——无返回值函数的调用,可作为一条独立的语句。例如,printf()、scanf()等库函数的调用,均作为一条独立的语句。②表达式方式——有返回值函数作为表达式的一项,以函数返回值参与表达式的运算。例如,“max=max(x,y)”是一个赋值表达式,把max()函数的返回值赋予变量max。11/14/202314(2)断点与函数调用的返回断点——被调用函数执行完毕,返回调用函数后继续执行的位置。调用函数中的断点位置分两种情况:①语句调用方式:断点为函数调用语句的下一条语句。例如,[案例7.1]中的语句调用“printf(……);”,其断点为该语句的下一条语句“getch();”。11/14/202315②表达式调用方式:断点为函数调用所在的表达式。例如,在[案例7.1]中,“printf(……,max(num1,num2));”语句中的表达式调用“max(num1,num2)”:其断点为该表达式调用所在的表达式“max(num1,num2)”(在本例中,“max(num1,num2)”函数调用既是表达式调用,本身又构成一个简单表达式)。11/14/2023167.1.3参数传递发生函数调用时,根据参数值的性质不同,将参数传递分为两种:(1)

值传递——参数值是一个一般数据(整形、实型、字符型数据等)。系统把实参值复制1份给形参;被调用函数结束时,形参值不能传回给实参。(2)

地址(引用)传递——参数值是一个地址。11/14/202317执行[案例7.1]时的参数传递:intmax(int

n1,int

n2){return(n1>n2?n1:n2);

}

main(){int

max(intn1,intn2);

intnum1,num2;

printf("inputtwonumbers:");

scanf("%d%d",&num1,&num2);

printf("max=%d\n",max(num1,num2));

}11/14/202318(1)形参变量只有在被调用时,才分配内存单元;调用结束时,立即被释放。因此,形参只有在该函数内有效。调用结束,返回调用函数后,则不能再使用该形参变量。(2)实参和形参占用不同的内存单元,即使同名也互不影响。11/14/2023197.1.4小结1.函数定义不允许嵌套。2.调用有参函数时,实参的个数和类型,必须与形参匹配。3.函数调用的两种方式与断点位置(1)语句方式:断点为函数调用语句的下一条语句。(2)表达式方式:断点为函数调用所在的表达式。11/14/2023204.参数传递分两种:(1)

值传递:单向传递。(2)

地址(引用)传递。[返回]11/14/2023217.2函数的嵌套调用和递归调用7.2.1函数的嵌套调用

[案例7.3]计算∑=1!+2!+……+n!(n∈[1,20]的整数,从键盘输入)。算法设计要点:本案例可以设计2个函数:factor()用于求n!;sum()通过调用factor()来实现求∑。程序框架如下(完整程序详见教材7.2.1):

11/14/202322……voidmain(){……

sum(num); /*调用函数sum()*/……}voidsum(intnum){……sum+=factor(loop); /*求累计和*/……}longfactor(intnum) /*求num的阶乘*/{……}11/14/202323在[案例7.3]中,主函数main()调用求和函数sum(),sum()又循环调用求阶乘的函数factor()。一般地说,函数的嵌套调用是指,在执行被调用函数时,该函数又调用其它函数的情形。注意:被调用函数执行完毕后,将返回到调用函数的断点继续执行。简言之,谁调用,返回到谁的断点继续执行。11/14/2023247.2.2函数的递归调用[案例7.4]用递归法计算n!(1!=1,n!=(n-1)!*n(n≥2))。算法设计要点:(1)根据计算n!的递归定义可知,为了计算n!,必须首先计算(n-1)!;以此类推,直至1!(1!=1)。(2)依据1!求2!=1!*2,再依据2!求3!=2!*3;同理,依据(n-1)!求n!=(n-1)!*n。11/14/202325longfactor(intnum){longfact;if(num>1)fact=factor(num–1)*num;elsefact=1;return(fact);}以num=5为例,其执行过程详见教材7.2.2。递归调用自己11/14/202326C语言允许函数直接(或间接)地调用它自己,称为递归调用;这种函数称为递归函数。例如,[案例7.4]中的函数factor()就是一个递归函数。防止递归调用无终止地进行的常用办法:添加1个继续(或终止)递归调用的条件判断。例如,[案例7.4]中函数factor()中的“if(num>1)”。[返回]11/14/2023277.3内部函数和外部函数

C语言程序中的函数,是通过被调用而执行的,所以一个函数需要被其它函数调用。但是,当一个程序由多个源文件组成时,在一个源文件中定义的函数,能否被其它源文件中的函数调用呢?C语言据此将函数分为内部函数和外部函数。11/14/2023287.3.1内部函数(又称静态函数)

如果在一个源文件中定义的函数,只能被本源文件中的其它函数调用,这种函数称为内部函数。1.定义static

函数类型函数名([形参表]){……}2.特点:只能被本文件中的函数所调用。3.好处:不用担心与其它源文件中的函数同名,因为即使同名也没关系。11/14/2023297.3.2外部函数如果在某源文件中定义的函数,可被同一程序中所有源文件中的函数调用,这种函数称为外部函数。1.定义:[extern]

函数类型函数名([形参表]){……}2.特点:允许被所有源文件中的函数所调用。3.调用其它源文件中的外部函数时,需要对其进行说明:[extern]

函数类型函数名([形参表])[,函数名2([形参表2])…];11/14/202330[案例7.5]

将加、减、乘、除和求余数运算练习程序(第3版))的源文件组织形式改为:实现加、减、乘、除和求余数运算的程序段,均作为1个独立的函数、存储在1个独立的源文件中。程序框架如下(完整程序详见案例源代码):11/14/202331……/*外部函数说明*/externvoidaddition(intn1,intn2);externvoidsubtraction(intn1,intn2);

externvoidmultiplication(intn1,intn2);externvoiddivision(intn1,intn2);externvoidremainder(intn1,intn2);voidmain(){……}11/14/2023327.3.3多个源文件的编译和连接在软件工程项目中,采用结构化方法进行程序设计与编程,通常会产生多个源文件(例如源程序文件、数据结构定义文件等)。那么,如何将这些源文件编译、连接成一个统一的可执行文件呢?一般有两种方法:11/14/202333(1)分别编译、一并连接C编译程序是以源文件为编译单位。当一个程序中的函数和数据结构分放在多个源文件中时:先将各文件分别编译,再通过link命令产生一个可执行文件(.exe)。

(2)集中编译、连接利用编译预处理命令#include,将其它源文件包含到主函数main()所在的源文件的开头;然后直接编译该文件即可。11/14/202334例如,在[案例7.5]中的主函数main()所在的源文件case75_1.c的开头添加如下几行:……/*将其它各源文件包含进来*/#include"case75_2.c"#include"case75_3.c"#include"case75_4.c"#include"case75_5.c"#include"case75_6.c"voidmain(){……}[返回]11/14/2023357.4*

内部变量与外部变量

C语言中的变量,定义位置不同,其作用域也不同,据此将变量分为内部变量和外部变量。7.4.1内部变量1、内部变量——在函数内(函数说明+函数体)定义的变量。2、作用域——只在该函数范围内有效。所以内部变量也称“局部变量”。11/14/202336例如,在[案例7.4]中,主函数main()中定义的变量num就是内部变量,它仅在主函数main()中才能使用;求阶乘的factor()函数,函数说明中的形参变量num,以及函数体中定义的变量fact,均属内部变量,都只能在factor()函数中使用。

说明:在不同的函数中,允许使用同名内部变量。它们代表不同的对象,互不干扰。例如,在[案例7.4]中,主函数main()中的内部变量num,与函数factor()中的内部变量num同名。11/14/202337[案例]内部变量的应用。voidmain(){voidsum(intnum);

int

num=100;

printf(“num_main()=%d\n”,num); /*调用前实参的值*/sum(num

); /*调用函数*/

printf("num_main()=%d\n",num); /*调用后实参的值*/

getch();}voidsum(intnum){inti;

printf("num_sum()=%d\n",num);/*改变前的形参值*/

for(i=num-1;i>=1;i--)num+=i;/*改变形参的值*/

printf("num_sum()=%d\n",num);/*改变后的形参值*/}11/14/2023387.4.2外部变量1、外部变量——在函数外部定义的变量。2、作用域:从外部变量的定义位置开始,到本文件结束为止。外部变量不从属于任何一个函数,可被作用域内的所有函数使用,所以外部变量又称全局变量。11/14/202339[案例7.6]

设计一个函数cuboid(intlength,intwidth,intheight)(3个参数依次为长方体的长、宽、高),用于求长方体的体积及正、侧、顶三个面的面积。算法设计要点:函数cuboid(intlength,intwidth,intheight)本身只能返回1个值(本案例选定体积),正、侧、顶三个面的面积就只能通过外部变量来进行数据共享。

参考程序框架如下:11/14/202340……longarea1,area2,area3; /*定义3个外部变量,用于数据共享*/longcuboid(intlength,intwidth,intheight); /*函数说明*/voidmain(){……volume=cuboid(length,width,height);

printf("\nvolume=%ld,area1=%ld,area2=%ld,area3=%ld",volume,area1,area2,area3);}11/14/202341longcuboid(intlength,intwidth,intheight){longvolume;volume=length*width*height; /*计算体积*/

area1=length*width; /*计算3个面的面积*/

area2=width*height;

area3=length*height; return(volume); /*返回体积值*/}11/14/2023423、说明(1)外部变量的作用域:从定义点到本文件结束。为方便使用,建议:将外部变量的定义放在文件开头,如[案例7.6]所示。(2)在同一源文件中,允许外部变量和内部变量同名。在内部变量的作用域内,外部变量不起作用。11/14/202343(3)外部变量可实现函数之间的数据共享,但又使这些函数依赖这些外部变量,因而使得这些函数的独立性降低。注:从模块化程序设计观点来看,这是不利的。因此不是非用不可时,不要使用外部变量。11/14/202344[案例]内部、外部变量的同名应用。int

len=3,width=4,high=5;int

vs(int

len,int

width){int

vol;

vol=len*width*high;/*引用外部变量high*/returnv;

}main(){int

len=5;

printf("len=%d,width=%d,high=%d,vol=%d",

len,width,high,vs(len,width));

}len=?width=?len=?11/14/2023457.4.3小结1.内部变量——在函数内(函数说明+函数体)定义的变量,其作用域:只在该函数范围内有效。不同函数中的同名内部变量,互不干扰。2.外部变量——在函数外部定义的变量,其作用域:从外部变量的定义位置开始,到本文件结束为止。允许内部、外部变量同名。在内部变量的作用域内,外部变量不起作用。[返回]11/14/2023467.5变量的存储特性

C语言中的变量,不仅有类型特性,还有存储特性:(1)动态存储方式:自动内部变量(auto)、寄存器变量(register)(2)静态存储方式:静态内部变量(static)、外部变量(extern)。11/14/2023477.5.1内部变量的存储1.动态存储──自动内部变量(简称自动变量)(1)定义:[auto]数据类型内部变量表;(2)存储特点:①作用域:局限于定义它的函数内。②生存期:函数被调用时,分配存储空间;调用结束就释放。③初始化:定义而不初始化,其值是不确定的。如果初始化,则每次调用都要重新赋一次初值。11/14/2023482.静态存储──静态内部变量(1)定义:static

数据类型内部变量表;(2)存储特点①作用域:不变(只在本函数内有效,其它函数不可引用)。②生存期:扩展到整个程序(即函数调用结束也不释放)。③初始化:定义但不初始化,则系统自动初始化:0(整型和实型)或‘\0’(字符型);每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值!11/14/202349

[案例7.7]输出1~4的阶乘,并展示自动变量与静态内部变量的存储特性。……voidmain(){intnum=1;for(;num<=4;num++)factorial(num);

getch();}voidfactorial(intn){staticlongfact=1; /*静态内部变量:只初始化1次*/

int

var_auto=0; /*自动变量:每次调用都重新初始化*/fact*=n; /*求n!*/

printf("var_auto=%d,%d!=%ld\n",var_auto,n,fact);++var_auto;}11/14/202350程序运行结果如下:

var_auto=0,1!=1

var_auto=0,2!=2

var_auto=0,3!=6

var_auto=0,4!=2411/14/2023517.5.2外部变量的存储与作用域外部变量属于静态存储。如果程序由多个源文件构成,根据某个源文件中定义的外部变量能否被其它源文件中的函数所引用,将外部变量分为两个作用域级别:(1)文件级外部变量──只允许被本源文件中的函数引用

static

数据类型外部变量表;说明:“static”直译为“静态”,很多书籍称之为“静态外部变量”。本书根据这种外部变量的作用域,称之为“文件级外部变量”。11/14/202352(2)程序级外部变量──允许被程序中、各源文件内的函数引用定义时,缺省static的外部变量,即为程序级外部变量。同一程序中的其它源文件内的函数,引用程序级外部变量时,需要进行说明:extern数据类型外部变量表;11/14/2023537.5.3小结关键字“static”对内部、外部变量的影响不同:(1)将内部变量改为静态存储:作用域未变,只扩展了它的生存期(函数→整个程序),且每次调用所在函数时,不再重新赋初值,只是保留上次调用结束时的值!(2)将外部变量改为static,缩小了它的作用域(整个程序→所在文件)。[返回]11/14/2023541、函数的定义[函数类型]函数名([形参表]){说明语句部分;可执行语句部分;}(1)函数定义不允许嵌套。(2)函数中无return语句,系统返回一个不确定的值。可以用“void”定义成“无(空)类型”,表示不返回值。本章要点11/14/2023552、函数调用:函数名([实参表])

对于有参函数:(1)必须提供实参表:实参的个数、类型必须与形参匹

温馨提示

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

评论

0/150

提交评论