收藏 分销(赏)

第8章函数.ppt

上传人:xrp****65 文档编号:13327798 上传时间:2026-03-02 格式:PPT 页数:48 大小:533.50KB 下载积分:10 金币
下载 相关 举报
第8章函数.ppt_第1页
第1页 / 共48页
第8章函数.ppt_第2页
第2页 / 共48页


点击查看更多>>
资源描述
,广东商,学院,华商学院,语言,第八章 函数,【,主要内容,】,本章主要讨论结构化程序设计的基本思想、函数定义、函数调用的方法、函数间相互通信的过程(参数传递)、变量作用域、变量的生命周期和变量的存储类别。,【,学习重点,】,重点掌握函数定义、函数调用方法、函数间参数传递的过程、变量作用域和存储类别,了解这些内容之后通过做本章的实训来巩固所学知识以达到熟练运用的目的。,第一节 函数概述,第二节 自定义函数的实现,第三节,变量作用域和存储类别,第八章 函数,第一节 函数概述,模块划分法,:,这种“分而治之”的方法是解决很多复杂问题的好方法。在程序设计语言中我们把这种方法称为“模块划分法”。,S1,b,a,S2,S3,求下图的面积,:,分别求半圆的面积,S1,、矩形的面积,S2,和等边三角形的面积,S3,,最后通过累加三个子面积之和而得到整个图形的面积。,第一节 函数概述,模块划分法是结构化程序设计的方法。结构化程序设计的思想包括以下,3,方面的内容:,任何一个程序都是由顺序结构、选择结构、循环结构这,3,种结构构成。,一个大程序应该按功能划分成一些小功能模块,并块根据它们之间的关系有机组织起来。现代软件工程要求在按功能划分模块时尽量遵守“低耦合高内聚”的原则,即各模块功能尽量独立,各模块间的联系尽量少。,程序设计方法应采用“自顶向下、逐步细化”的方法,第一节 函数概述,什么是函数,:,在,C,语言程序设计中通常将一个较大的程序分解成若干个较小的、功能单一的程序模块来实现,这些完成特定功能的模块称为函数。,函数是组成,C,语言程序的,基本单位,。,C,语言的函数有两种:,标准函数,和,自定义函数,。前者已经由系统提供,如,sin(x,),、,sqrt(x,),等,这类函数只要用户在程序的首部把相应的头文件包括进来即可直接调用;后者是程序员根据需要自己定义的函数。本章主要讨论自定义函数的定义与引用方法。,1.,请列举出,10,个标准函数,并说明这些函数的功能及使用方法。,课堂练习,8.1,第一节 函数概述,第二节 自定义函数的实现,一、自定义函数示例,自定义函数有各种分类法。按,参数的个数,,分为无参自定义函数、有参自定义函数两种;按,是否有返回值,,分为无返回值、返回单值、返回多值自定义函数三种;按,是否有函数体,,分为空函数、非空函数两种。,第二节 自定义函数的实现,【,例,8-1】,请先输入两个数作为一个区间的上限与下限,然后再找出该区间内所有能够同时被,3,和,5,整除的数,并统计这些数的个数。,【,简要分析,】,定义一个函数,search(),实现该功能。因为用户输入两个数时是不考虑大小顺序的,所以程序必须判断这两个数的大小,以确定区间的上限和下限。设一个变量来统计满足条件的数的个数,变量名,含义,类型,初值,upda,区间的上限,int,键盘输入,downda,区间的下限,int,count,统计个数,int,0,temp,临时保存数据,int,任意,用自然语言描述程序逻辑:,设置相关环境,按表,8-1,定义变量。,初始化变量,upda,、,downda,、,count,。,判断,upda,、,downda,的大小关系,如果,upda,小于,downda,则交换之。,逐个判断在这个区间内的所有数,从中找出满足条件的数并统计其个数。,输出结果,结束。,第二节 自定义函数的实现,第二节 自定义函数的实现,1.,无参数自定义函数,主函数与自定义的功能拟这样分配:主函数只完成调用,利用自定义函数实现本例的全部功能。,源代码,:,请阅读下边的程序,注意,search(),函数是怎样从主函数中分离出去的。,运行输出:,please input two integer data:98,18,30 45 60 75 90,count=5,本例,search(),函数这样圆括号内是空的,没有参数,称为无参数自定义函数,简称无参函数,且该函数本身也没有返回值,所以它的类型为空类型(,void,)。,第二节 自定义函数的实现,无参自定义函数,的定义格式是:,类型说明符 函数名,(),说明部分,;/*,变量说明*,/,语句部分,;,第二节 自定义函数的实现,函数定义的几点规则:,“类型说明符”说明自定义函数的返回值类型,它可以是,C,语言的基本数据类型或空类型(,void,),书写时要注意该行后无分号。其实,任何函数都有返回类型,如,sqrt(x,),返回值是双精度型(,double,),,strlen(str,),返回值是整型(,int,)。,函数名是唯一标识一个函数的合法标识符,在一个程序中具有唯一性,也就是说在一个,C,程序中不能有同名的函数存在。函数名的取名方法与变量同。,函数名后的一对圆括号是函数的标志,其内放置参数。对无参函数来说圆括弧内没有参数,是空的,但圆括号本身不能省略。,两个花括号括起来的部分称为函数体,它由说明部分和语句部分组成。当然函数体内也可以无语句,俗称空函数;该函数什么也不做只是占一个位置,在程序需要扩充功能时,再编写。空函数不影响程序的正常运行。,第二节 自定义函数的实现,【,思考验证,】,当程序运行时,是先执行主函数还是自定义函数?请单步运行该程序。,【,融会贯通,】,写自定义函数,fun(),实现:找出所有三位自然数中三位数字之和是,6,的数,并统计其个数。,提示:,一个,C,语言程序必须有且只有一个名为,main(),的主函数,无论,main(),函数位于程序的什么位置,运行时总是从,main(),函数开始,最后结束于,main(),函数。,C,语言中函数不能嵌套定义,但能嵌套调用。所谓嵌套定义是指在一个函数的函数体内再定义另外一个函数。,自定义函数必须先定义后调用。本例,main(),函数中的“,search();”,语句是对自定义函数,search(),的调用。,第二节 自定义函数的实现,2.,有参数自定义函数,【,例,8-1_2】,【,例,8-1】,的另外一种写法如下:,源代码:,有参函数定义格式,:,类型说明符 函数名,(,形式参数列表,),说明部分,;,语句部分,;,第二节 自定义函数的实现,形式参数与实际参数的概念:,形式参数,:在定义函数时,写在自定义函数名后一对圆括号内的变量称为形式参数,简称形参。形参只能是变量,不能是表达式或常量,形参也可以为空,实际参数,:在调用自定义函数的语句中,写在函数名后一对圆括号内的参数称为实际参数,简称实参。实参可以是常量、变量或任何有确定值的表达式,甚至是数组名、指针、结构变量等,实参与形参的关系,一般遵守“类型匹配、个数相同、按位置一一对”的原则。,形参与实参可以是一个或多个,也可以没有,视具体情况而定。当有多个形参或实参时,各参数之间用逗号隔开。,形参与实参只是类型相同,没有直接关系,所以二者可以同名(即使同名,也互不影响),也可以不同名。,在自定义函数体中形参可以被引用,如输入、输出、被赋以新值、或参与运算,形参是局部变量,其值只在自定义函数体内有效,一旦离开自定义函数,其值自动消亡。,第二节 自定义函数的实现,3.,有返回值的自定义函数,C,语言提供了多种方法实现函数之间信息互通。当需要从自定义函数中返回一个值时,可在自定义函数中使用返回语句。返回语句的关键字是:,return,。,例,8-1_2.c,中,能不能在主函数,main(),中输出满足条件的数的个数呢?这其实是函数之间怎样互通信息的问题。,本例希望,search(),函数的值为满足题设条件的数之个数,故,search(),函数的类型为整型(,int,)。下边的源代码就是按些思路编写的:,?,第二节 自定义函数的实现,第二节 自定义函数的实现,本例调用,search(),函数的方式为,表达式调用,,它与输出行可以合并为一行:,printf(“nthe,number is%d”,search(start,end);,这样,自定义函数成了输出函数的参数,这种调用自定义函数的方式称,参数调用,。,参考源代码,:(例,8-1_3,),第二节 自定义函数的实现,带返回值的函数调用过程图,:,该过程用一个比方描述:我们正读一篇英语文章;遇到了一个生词;于是我们转去查字典;弄清楚了生单词后,我们返回原文断点处继续往下读。,带一个返回值函数的定义格式:,类型说明符 函数名(形式参数列表),说明部分;,语句部分;,return (,表达式 或 变量,);,第二节 自定义函数的实现,第二节 自定义函数的实现,说明几点:,返回语句的格式也可简写成如下格式:,return,表达式或变量,;,函数类型为,void,的函数,表示该函数被调用后无返回值,在函数体内可以不写,return,语句,也可只写“,return;”,表示返回到主调函数。没有,return,语句的函数在被调用时返回不确定的值。,自定义函数类型一般要与,return,语句后表达式值的类型相匹配。,系统默认的返回值类型为,int,,当函数的返回值为,int,类型数据时,在定义函数时可以省略函数类型说明(,int,)。,return,语句只能从自定义函数返回一个值,第二节 自定义函数的实现,二、自定义函数声明,前后的例题中,自定义函数是写在主函数之前的。当然自定义函数也可放在主函数之后,这样的好处是整个程序结构清晰,主干在前,枝叶在后,便于阅读和理解。但采用这种方法要先对函数作原型声明。,下面的代码是对,8-1_3.c,的改进:,例,8-1_4,源代码:,想一想,跟前面的例题有什么区别?,第二节 自定义函数的实现,为什么要对自定义函数进行声明呢?原因如下:,如果在函数调用之前,没有对函数作声明,则编译系统会把第一次遇到 的该函数形式(函数定义或函数调用)作为函数的声明,并将函数类型默认为,int,型。所以,当一个函数的类型不是,int,型并且没有在调用它之前声明,那么,在编译时就会出错。,所谓函数原型声明就是这样一条语句:原样书写自定义函数的函数头,然后再写上分号“,;”,即可,如,8-1_4.c,中语句,:,void search(,int,downda,int,upda,),;,为了确保函数调用时,编译程序检测形参和实参类型、个数是否相同等基本信息,就必须通过一种方法来告诉编译程序被调函数是怎样定义的,,C,语言正是通过,函数原型,的方法来保证函数之间的正确调用。,函数声明与函数定义是完全不同的两回事。前者只说明函数的外在特性,后者是函数功能的具体描述。,第二节 自定义函数的实现,三、自定义函数调用,在,C,语言中,主要是通过实参和形参实现函数间的信息传递。其方式有两种,“,值传递,”和“,地址传递,”。,值传递,:在函数调用时,主调函数将各实参(常量、变量、数组元素、计算表达式)的值一一对应地传递给被调函数的各形参。,调用函数,创建形参,实参值赋给形参,执行被调函数,返回主调函数,释放形参,地址传递,:在函数调用时,实参传递给形参的是实参变量在内存中所占存储空间的首地址。由于地址的唯一性,实参和形参实际上使用的是同一块存储空间,.,下边源代码调用函数采用的是地址传递,/*,例,8-1,,,8-1_5.c*/,参考源代码,:,第二节 自定义函数的实现,运行输出:,请输入两个整数:,10,100,153045607590,count=6,主函数,main(),中调用函数,search(),的语句为:,search(,两个实参前均加了地址运算符“,&”,,表示传递给形参的值不再是变量,start,、,end,的值,而是它们在内存中的地址。当然,要求对应的形参也必须是同类型的地址变量,值传递”与“地址传递”两种参数传递方式的的区别是:,作为“地址传递”的典型应用,数组作函数参数有普遍而重要的实际意义。形参如果是一维数组则可以不指定数组的长度,如果是多维数组,除第一维的长度可以不指定外,其余各维的长度必须指定;形参数组中某一元素的值改变,也会改变实参数组中的相应元素的值;函数调用时,实参数组和形参数组可以同名,也可以不同名。,第二节 自定义函数的实现,“值传递”的形参和实参各占独立的存储单元,形参中保存的是实参的一个拷贝,当然完成这个拷贝要花费系统时间;,“地址传递”的形参和实参都是地址,形参和实参占用的是同一片内存单元,实参勿需传值给形参,所以这种方式既节省空间又节省时间。更优越的是,采用地址传递方式,能使自定义函数返回多个值。,【,例,8-2】,求,N*N,的整型矩阵对角线元素之积。,第二节 自定义函数的实现,【,简要分析,】,如图:方格外的数字分别代表行号、列号,阴影部分是两条对角线。不难看出对角线元素下标的规律,斜线标出的对角线是主对角线,它的每一个元素所在的行号和列号相同,竖线标出的是次对角线,它的每一个元素所在的行号递增和列号递减。,0 1 2 3 4,0 1 2 3 4,1,long,乘积,product,从实际参数得来,int,数组,ayN,0,int,行,/,列号,i,j,输入,int,二维数组,arrayNN,5,int,数组的长度,N,初值,类型,含义,变量名,变量表:,设置相关环境,定义变量;,初始化变量,arrayNN,,,product,;,计算矩阵对角线之积;,输出结果,结束。,第二节 自定义函数的实现,用自然语言描述的程序逻辑:,参考源代码:,【,融会贯通,】,请修改本例,实现求周边元素之积。,【,思考验证,】,如果将函数,mul,(),的形参说明成指针*,p,,函数体,应该怎么写?,1.,函数的嵌套调用,在,C,语言中,函数的定义是平行的,不允许函数嵌套定义(即在一个自定义函数体中又定义另一个新的自定义函数),但函数之间可以嵌套调用,即允许在一个函数体内再调用其他函数。,第二节 自定义函数的实现,【,例,8-3】,有,1010,的二维数组,求各行最大元素之和。,【,简要分析,】,可以视为,10,个一维数组,求一维数组中的最大值,循环,10,次即可。拟定义,3,个自定义函数,这样分工:,create(),产生并输出原始数据;,searchmax,(),找出一行上的最大元素;,calculate(),循环,10,次,把各行上的最大数累加起来。设变量表如表,8-3,。,变量名,含义,类型,初值,N,数组长度,int,10,arrayNN,二维数组,int,输入,a,一维数组,int,从实参的来,i,j,行列号,int,0,sum,求和,int,0,第二节 自定义函数的实现,用自然语言描述程序逻辑:,设置相关环境;,定义变量,实参,array1010,形参,a10,行,列号,i,j,,最大值,max,,和,sum,;,初始化变量,array1010,;,i=0,;,i10,成立吗?成立则做,,否则做,;,j=0,;,max=,aj,;,j,aj,成立吗?成立则做,j+,转,,否则做,;,交换,max,和,aj,的值,做,j+,转,;,sum+=max,i+;,转,;,输出结果,结束。,第二节 自定义函数的实现,参考源代码:,第二节 自定义函数的实现,函数嵌套调用过程示意图:,calculate(x,);,sum+=,searchmax(arrayi,);,main(),函数,calculate(),函数,searchmax(int,a),函数,【,思考验证,】,可以将,int,searchmax,(),定义在,calculate(),函数体内部吗?,【,融会贯通,】,用函数嵌套调用的方法,找出大于,M,的,N,个素数。要求统计大于,M,的,N,个数用,count(M,N,),实现,判断某数是否为素数用一个函数,flag(x,),实现。,2.,函数的递归调用,递归调用:,就是在调用一个函数过程中又直接或间接调用该函数本身。,递归算法的思想,:要解决某个问题,可以把这个问题分解成对,m,个子问题分别求解,如果子问题的规模仍然不够小,则再划分为,m,个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。,第二节 自定义函数的实现,什么是递归调用,?,【,例,8-4】,利用函数的递归调用求,x,的,n,次方。,【,简要分析,】,递归有两个阶段,第一阶段是“回推”,欲求,x,的,n,次方,回求,x,的,n-1,次方,再加求,x,的,n-2,次方,,当回推到,x,的,0,次方时,此时能够得到,x,的,0,次方为,1,,就不再回推了;然后进入第二阶段“递推”,由,x,的,0,次方开始,求,x,的,1,次方,,x,的,2,次方,,直到,x,的,n,次方。,变量名,含义,类型,初值,x,底数,int,输入,n,幂指数,int,输入,result,计算结果,int,0,第二节 自定义函数的实现,求,5,的,3,次方为例,递归调用的过程,:,x*xpower(5,1),xpower,函数,x*xpower(5,0),xpower,函数,xpower(5,0)=1,xpower(5,1)=5,xpower,(5,3),输出计算结果,main(),x*xpower(5,2),xpower,函数,xpower(5,2)=25,第二节 自定义函数的实现,参考源代码:,须要说明的是,一个问题能用递归方法求解,必须符合两个条件:,【,融会贯通,】,有,5,个人坐在一起,问第,5,个人多少岁,他说比第,4,个人大,2,岁,问第,4,个人的岁数,他说比第,3,个人大,2,岁,问第,3,个人的岁数,他说比第,2,个人大,2,岁,问第,2,个人,他说比第,1,个人大,2,岁,问第一个人,他说是,10,岁。请问第,5,个人的岁数?,第二节 自定义函数的实现,可将一个问题转化为具有同样解法的规模较小的问题。,必须有明确的结束条件。,课堂练习,8.2,1.,任意输入一个整数,判断它是几位数,并求其各位数之和。,2.,一天有个年轻人来到王老板的店里买了一件礼物,这件礼物的成本比标价少,10,元钱。这个年轻人掏出,100,元要买这件礼物,王老板当时没有零钱,用那,100,元向街坊换了,100,元的零钱,找给年轻人,3,倍于成本的钱。但是街坊后来发现那,100,元是假钞,王老板无奈还了街坊,100,元。现在问题是,:,王老板在这次交易中损失了,190,元钱,问这件礼物的标价是多少,?,第二节 自定义函数的实现,第三节 变量作用域和存储类别,一、变量作用域,变量作用域是指程序中声明的变量在程序的哪些部分是可用的。从变量作用域的角度,变量分为局部变量和全局变量两种。,局部变量,:在函数或复合语句内部定义的变量。该变量只在本函数或复合语句内部范围内有效。形参也是局部变量。,全局变量,:在函数体外定义的变量。全局变量的作用域是从它的定义行到整个程序的结束行。,【,例,8-5】,分析以下程序,理解变量的作用域。,源代码,:,运行输出:,a=3,b=4,st,=15,a=1,b=2,st,=0,【,思考验证,】,在不同的函数内定义同名局部变量,各个变量的作用域。,【,融会贯通,】,将上例中的复合语句块改写成一个函数,观察运行结果。,第三节 变量作用域和存储类别,二、变量的存储类别,从变量的生存期来分,变量分为,静态存储方式,和,动态存储方式,。,C,语言把用户的存储空间分成三部分:,程序区、静态存储区、动态存储区,。,全局变量、局部静态变量,形参变量,局部动态变量(,auto,register,),函数调用现场保护和返回地址等,程序区,静态存储区,动态存储区,第三节 变量作用域和存储类别,存储类别是指变量存放的位置。局部变量可以存放于内存的动态区、静态区和,CPU,的寄存器里,在程序里,我们可以把变量对应地定义为,自动,(,auto,)、,静态,(,static,),、,寄存器,(,register,)类别。,静态变量,:这种类别的变量在源程序运行期间,从开始到结束的整个过程一直占用固定存储空间。,动态变量,:这种类别的变量当进入它的函数或复合语句时才分配存储空间,一旦离开它所在的函数或复合语句则立即释放所占的存储空间。,第三节 变量作用域和存储类别,1.,静态变量,在使用静态变量时,要,注意,下面三点:,在函数多次被调用的过程中,静态局部变量只被初始化一次,并且其值具有可继承性,即前一次调用产生的结果会保留并参与下一次调用的运算中。,静态变量的初始化是在编译时进行的,在定义时只能使用常量或常量表达式进行显示初始化,未初始化时,编译将它初始化为,0,(数值型)或空字符(字符型)。,静态局部变量的值只能在定义它的函数体内使用。,第三节 变量作用域和存储类别,【,例,8-6】,分析以下程序的运行结果,理解静态变量的作用。,源代码:,运行输出:,st,=0,st,=1,st,=2,st,=3,st,=4,st,=5,st,=6,st,=7,st,=8,st,=9,【,思考验证,】,把此例中的静态变量,st,,改为自动变量,看结果又是什么?,【,融会贯通,】,在,add,函数中用静态变量求,(0,,,300),内所有奇数之和,主函数已给出,请完成,add,函数。,void main(),int,i=0,;,for(;i 150;i+),add(),;,/*,函数调用求奇数和*,/,第三节 变量作用域和存储类别,2.,自动变量,(auto),自动变量是,C,程序中使用最多的一种变量,因为它的创建和撤消都是由系统在程序执行过程中自动进行的所以称为自动变量。,自动变量的声明格式,:,auto,数据类型 变量名,=,变量,|,表达式,auto,是自动变量存储类别的标识符,如果省略了,auto,,系统默认此变量为自动变量。,例如,以下变量都是局部自动变量:,void fun(),int,var1=0;,auto char str3;,第三节 变量作用域和存储类别,3.,寄存器变量,(register),寄存器变量存储在,CPU,的寄存器中,所以存取速度最快,。,定义寄存器变量的,格式,:,register,数据类型 变量名,=,变量,|,表达式,第三节 变量作用域和存储类别,课堂练习,8.3,1.,以下程序运行后的结果是:,_,int,fun(,int,n),static,int,f=1,;,f*=n,;,return f,;,main(),int,i,a5;,for(i=1;i=5;i+),ai-1=,fun(i,);,printf(“%d,”,a3);,第三节 变量作用域和存储类别,2.,以下程序运行后的结果是:,_,int,fun(),auto,int,x=1;,static,int,y=1;,x+=2;y+=2;,return,x+y,;,main(),int,a,b;,a=fun();b=fun();,printf(“%d,%d n”,a,b);,第三节 变量作用域和存储类别,本章结束,
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 百科休闲 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服