第6章 函数优秀PPT.ppt
第6章 函数现在学习的是第1页,共134页第第6 6章章 函数函数本章的学习目标本章的学习目标:l了解模块化程序设计的概念;了解模块化程序设计的概念;l了解库函数、自定义函数的区别;了解库函数、自定义函数的区别;l掌握函数的定义和调用;掌握函数的定义和调用;l掌握变量的性质,包括作用域和生命期;掌握变量的性质,包括作用域和生命期;l能创建多文件的程序:项目。能创建多文件的程序:项目。2现在学习的是第2页,共134页本本 章章 概概 要要6.1 6.1 概述概述6.2 6.2 函数的定义函数的定义6.36.3函数的调用函数的调用6.4 6.4 常见的库函数(自学)常见的库函数(自学)6.5 6.5 变量的性质变量的性质6.66.6变量的作用域变量的作用域6.76.7变量的生命期变量的生命期6.86.8内部函数与外部函数内部函数与外部函数3现在学习的是第3页,共134页引引 例例 1 1:大:大 话话 三三 国国懿问曰:“孔明寝食及事之烦简若何?”使者曰:“丞相夙兴夜寐,罚二十以上皆亲览焉。所啖之食,日不过数升。”懿顾谓诸将曰:“孔明食少事烦,其能久乎?”这给程序设计带来这给程序设计带来什么启示?什么启示?4现在学习的是第4页,共134页引引 例例 2:2:秦国武器的过人之处秦国武器的过人之处 秦国军队使用的弩是当时世界上最先进的,但其实最先进的秦国军队使用的弩是当时世界上最先进的,但其实最先进的不仅是弩的制作工艺,而更在于科学的管理制度。工匠们在制作不仅是弩的制作工艺,而更在于科学的管理制度。工匠们在制作弩的过程中,并不是每个工匠都独立制作一个完整的弩,而是每弩的过程中,并不是每个工匠都独立制作一个完整的弩,而是每种工匠专职制作一种部件,最后进行拼接。这样进行分工则每种种工匠专职制作一种部件,最后进行拼接。这样进行分工则每种工匠只需要专注于一种工作,技术相对更加娴熟,使得工作更象工匠只需要专注于一种工作,技术相对更加娴熟,使得工作更象流水线作业,大大地提高了效率不说,培训这样的工匠也相对成流水线作业,大大地提高了效率不说,培训这样的工匠也相对成本比较低。而且大家都只专注自己的那部分技术而并不明白其他本比较低。而且大家都只专注自己的那部分技术而并不明白其他部件的制作工艺,还可以防止个人可以独立制作武器而造成不安部件的制作工艺,还可以防止个人可以独立制作武器而造成不安全的因素。全的因素。5现在学习的是第5页,共134页6.1 6.1 概述概述上上述述的的管管理理模模式式其其实实是是一一种种模模块块化化分分工工与与合合作作的的思思想想。为为了了在在C C语语言言中中实实现现模模块块化化的的思思想想,就就要用到函数。本章主要介绍函数的基础知识。要用到函数。本章主要介绍函数的基础知识。6现在学习的是第6页,共134页模块化程序设计模块化程序设计l基本思想:将一个大的程序按功能分割成一些小模块。基本思想:将一个大的程序按功能分割成一些小模块。l特点:特点:各模块相对独立、功能单一、结构清晰、接口简单。各模块相对独立、功能单一、结构清晰、接口简单。控制了程序设计的复杂性。控制了程序设计的复杂性。提高元件的可靠性。提高元件的可靠性。缩短开发周期。缩短开发周期。避免程序开发的重复劳动。避免程序开发的重复劳动。易于维护和功能扩充。易于维护和功能扩充。l开发方法开发方法:自上向下自上向下,逐步分解,分而治之逐步分解,分而治之6.1 6.1 概述概述7现在学习的是第7页,共134页模块化的优点模块化的优点l模块各司其职模块各司其职每个模块只负责一件事情,它可以更专心每个模块只负责一件事情,它可以更专心便于进行单个模块的设计、开发、调试、测试和维护便于进行单个模块的设计、开发、调试、测试和维护等工作等工作一个模块一个模块地完成,最后再将它们集成一个模块一个模块地完成,最后再将它们集成l开发人员各司其职开发人员各司其职按模块分配任务,职责明确按模块分配任务,职责明确并行开发,缩短开发时间并行开发,缩短开发时间l分而治之(分而治之(Wirth,1971Wirth,1971)信息隐藏(信息隐藏(Parnas,1972Parnas,1972)8现在学习的是第8页,共134页6.1 6.1 概述概述6.1.2 6.1.2 什么是函数什么是函数 l函数是一组逻辑相关语句的集合。函数是一组逻辑相关语句的集合。lC C语言中,模块就是一组逻辑相关语言中,模块就是一组逻辑相关(这也体现了软这也体现了软件工程中的件工程中的“内聚性内聚性”)的语句的集合或说是用于的语句的集合或说是用于完成特定任务的程序代码的单元。完成特定任务的程序代码的单元。l根据规模的大小,根据规模的大小,C C语言中的模块有三种形式,它语言中的模块有三种形式,它们是:们是:语句块语句块(即复合语句)、(即复合语句)、函数函数和和文件文件。l函数是函数是C C语言中最为常用的模块单元,因此通常说语言中最为常用的模块单元,因此通常说C C程序是由函数组成的,函数是程序是由函数组成的,函数是C C语言程序的基本语言程序的基本组成部分。组成部分。9现在学习的是第9页,共134页maincabdefghijkl图 6-1 C程序的模块化6.1 6.1 概述概述10现在学习的是第10页,共134页lC C是是函数式函数式语言语言l必须有且只能有一个名为必须有且只能有一个名为mainmain的主函数的主函数lC程序的执行总是程序的执行总是从从mainmain函数开始函数开始,在在mainmain中结束中结束6.1 6.1 概述概述C程序结构11现在学习的是第11页,共134页函数分类函数分类l从用户角度从用户角度:标准函数(库函数):由系统提供标准函数(库函数):由系统提供用户自定义函数用户自定义函数l从函数形式从函数形式:无参函数无参函数有参函数有参函数使用使用库函数库函数应注意:应注意:1、函数功能、函数功能2、函数参数的数目和顺序,及各参数意义和类型、函数参数的数目和顺序,及各参数意义和类型3、函数返回值意义和类型、函数返回值意义和类型4、需要使用的包含文件、需要使用的包含文件6.1 6.1 概述概述12现在学习的是第12页,共134页6.2 6.2 函数的定义函数的定义函数在函数在定义定义的时候是平等的,即一个函数不的时候是平等的,即一个函数不能由另一个函数所定义;但是一个函数可以被另能由另一个函数所定义;但是一个函数可以被另一个函数所调用。一个函数所调用。换句话说,函数换句话说,函数可以嵌套调用但是不可以嵌可以嵌套调用但是不可以嵌套定义套定义。13现在学习的是第13页,共134页6.2.26.2.2函数的定义函数的定义函数体函数体合法标识符合法标识符函数返回值类型函数返回值类型缺省缺省int型型无返回值无返回值void函数类型函数类型 函数名(形参类型说明表)函数名(形参类型说明表)说明部分说明部分;语句部分语句部分;return 语句语句;函数头部函数头部6.2 6.2 函数的定义函数的定义14现在学习的是第14页,共134页6.2 6.2 函数的定义函数的定义说明说明:l参数:参数一般用于一个函数把数据传递给另一参数:参数一般用于一个函数把数据传递给另一个函数(调用者和被调用者之间),实现函数之个函数(调用者和被调用者之间),实现函数之间的通信。这是很重要的,因为在模块化分工合间的通信。这是很重要的,因为在模块化分工合作的工作模式中,函数参数实现了各个模块之间作的工作模式中,函数参数实现了各个模块之间的通信才使得各个模块得以彼此协作。定义函数的通信才使得各个模块得以彼此协作。定义函数的时候,函数的参数是形式参数,是对一件具体的时候,函数的参数是形式参数,是对一件具体事件可能需要数据的假设。事件可能需要数据的假设。15现在学习的是第15页,共134页6.2 6.2 函数的定义函数的定义l返回值:返回值就好比做了一件事情,这个事情的返回值:返回值就好比做了一件事情,这个事情的完成带回来了个结果。在定义函数的时用完成带回来了个结果。在定义函数的时用“返回值返回值类型类型”指定函数的类型,即函数带回来的值的类型。指定函数的类型,即函数带回来的值的类型。如果类型标识符为如果类型标识符为voidvoid则表示不需要带回函数值;则表示不需要带回函数值;而如果没有类型标识,则而如果没有类型标识,则TC2.0TC2.0默认返回值类型是默认返回值类型是intint(在(在vc+6.0vc+6.0中则认为默认为中则认为默认为voidvoid,视编译器,视编译器的不同而不同)。的不同而不同)。16现在学习的是第16页,共134页6.2 6.2 函数的定义函数的定义l函数体:一对花括号里面的内容函数体:一对花括号里面的内容(包括声明部分和包括声明部分和语句部分语句部分)又被称为函数体,当函数体为空的时候,又被称为函数体,当函数体为空的时候,该函数也被叫做该函数也被叫做空函数空函数,就是说它什么也不做。,就是说它什么也不做。void dummy()void dummy()17现在学习的是第17页,共134页例例6-1 6-1 定义一个函数,功能为:计算两个整数的平均数。定义一个函数,功能为:计算两个整数的平均数。/*/*函数功能:计算平均数函数功能:计算平均数函数入口参数:整型函数入口参数:整型x x,存储第一个运算数,存储第一个运算数 整型整型y y,存储第二个运算数,存储第二个运算数函数返回值:平均数函数返回值:平均数*/int Average(int x,int y)int Average(int x,int y)int result;int result;result=(x+y)/2;result=(x+y)/2;return result;return result;6.2 6.2 函数的定义函数的定义18现在学习的是第18页,共134页6.2.3 6.2.3 函数的参数和返回值函数的参数和返回值1.1.函数的参数函数的参数 大多数情况下,调用者大多数情况下,调用者(主调函数主调函数)和被调用者和被调用者(被调用函数被调用函数)之间有数据之间有数据传递关系,也就是说该函数有参数(可以称为有参函数,否则叫做无参函数)传递关系,也就是说该函数有参数(可以称为有参函数,否则叫做无参函数)。在定义函数时函数名后面括号中的参数称为。在定义函数时函数名后面括号中的参数称为“形式参数形式参数”(简称(简称“形参形参”);在主调函数中调用一个函数时,函数名后面括号中的参数(可);在主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个表达式)称为以是一个表达式)称为“实际参数实际参数”(简称(简称“实参实参”)。)。2.2.返回值返回值通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数的通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值,也称函数值。返回值,也称函数值。6.2 6.2 函数的定义函数的定义19现在学习的是第19页,共134页6.3.1 6.3.1 函数调用的一般形式函数调用的一般形式 函数名函数名(实参表列实参表列);6.3 6.3 函数的调用函数的调用20现在学习的是第20页,共134页6.3 6.3 函数的调用函数的调用如果是调用无参函数,则如果是调用无参函数,则“实参表列实参表列”可以没有,但是括号可以没有,但是括号不能省略。如果实参表列包含多个实参,则各个参数间用逗号隔不能省略。如果实参表列包含多个实参,则各个参数间用逗号隔开。开。实参和形参个数应相等,类型应匹配。实参与形参按实参和形参个数应相等,类型应匹配。实参与形参按顺序对应,一一传递数据。但应说明,如果实参表列包括顺序对应,一一传递数据。但应说明,如果实参表列包括多个实参,对实参求值的顺序并不是确定的,有的系统按多个实参,对实参求值的顺序并不是确定的,有的系统按自左至右顺序求实参的值,有的系统则按自右至左的顺序。自左至右顺序求实参的值,有的系统则按自右至左的顺序。1.1.实参与形参实参与形参个数相等,类型一致个数相等,类型一致,按顺序一一对应按顺序一一对应;2.2.实参表求值顺序视系统而定实参表求值顺序视系统而定(Turbo C(Turbo C,VC+VC+自右向左自右向左)。21现在学习的是第21页,共134页6.3 6.3 函数的调用函数的调用例例6-2 6-2 调用函数时的数据传递。调用函数时的数据传递。#include#include void main()void main()int max(int x,int y);int max(int x,int y);int a,b,c;int a,b,c;scanf(%d,%d,&a,&b);scanf(%d,%d,&a,&b);c=max(a,b);c=max(a,b);printf(max is%d,c);printf(max is%d,c);int max(int x,int y)/*int max(int x,int y)/*定义有参函数定义有参函数max*/max*/int z;int z;z=xy?x:y;z=xy?x:y;return(z);return(z);运行情况:运行情况:7,87,8max is 8max is 822现在学习的是第22页,共134页6.3 6.3 函数的调用函数的调用例例6-36-3返回值类型与函数类型不同。返回值类型与函数类型不同。#include#include void main()void main()int max(int x,int y);int max(int x,int y);float a,b;float a,b;int c;int c;scanf(%f,%f,&a,&b);scanf(%f,%f,&a,&b);c=max(a,b);c=max(a,b);printf(max is%d,c);printf(max is%d,c);int max(float x,float y)int max(float x,float y)float z;float z;/*z/*z为实型变量为实型变量*/z=xy?x:y;z=xy?x:y;return(z);return(z);运行情况:运行情况:1.51.5,2.5 2.5 max is 2max is 2以函数类型为准以函数类型为准23现在学习的是第23页,共134页6.3 6.3 函数的调用函数的调用c=max(a,b);c=max(a,b);(mainmain函数)函数)c=max(x,y);c=max(x,y);(maxmax函数)函数)int z;int z;z=xy?x:y;z=xy?x:y;return(z);return(z);图图 6-2 6-2 函数调用函数调用参参数数传传递递返返回回(有有返返回回值值)函函数数调调用用24现在学习的是第24页,共134页6.3 6.3 函数的调用函数的调用例例6-4 6-4 实参求值的顺序。实参求值的顺序。#include#include void main()void main()int f(int a,int b);/*int f(int a,int b);/*函数声明函数声明*/int i=2,p;int i=2,p;p=f(i,+i);/*p=f(i,+i);/*函数调用函数调用*/printf(%dn,p);printf(%dn,p);int f(int a,int b)/*int f(int a,int b)/*函数定义函数定义*/int c;int c;if(ab)c=1;if(ab)c=1;else if(a=b)c=0;else if(a=b)c=0;else c=-1;else c=-1;return(c);return(c);在在Turbo C 2.0Turbo C 2.0和和Turbo C+3.0Turbo C+3.0系统上运行的结果是系统上运行的结果是?在在Turbo C 2.0Turbo C 2.0和和Turbo C+3.0Turbo C+3.0系统上,若系统上,若p=f(i,i+);p=f(i,i+);结果是结果是?25现在学习的是第25页,共134页函数调用过程中形参和实参间数值传递的说明:函数调用过程中形参和实参间数值传递的说明:a)在定义函数中指定的形参,在函数尚未被调用时,它们并不占用内存中的存储单在定义函数中指定的形参,在函数尚未被调用时,它们并不占用内存中的存储单元。元。只有在发生函数调用时,函数只有在发生函数调用时,函数max中的形参才被分配内存单元。在调中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放用结束后,形参所占的内存单元也被释放。b)实参可以是常量、变量或表达式,例如:实参可以是常量、变量或表达式,例如:max(3,a+b);但要求它们有确定但要求它们有确定的值;的值;形参一定是变量表达式。形参一定是变量表达式。c)在被定义的函数中,必须指定形参的类型。在被定义的函数中,必须指定形参的类型。d)实参与形参的类型应相同或赋值兼容。例实参与形参的类型应相同或赋值兼容。例6-2中实参和形参都是整型,这是合法的、中实参和形参都是整型,这是合法的、正确的。如果实参为整型而形参正确的。如果实参为整型而形参x为实型,或者相反,则按照前面章节介绍的不为实型,或者相反,则按照前面章节介绍的不同类型数值的赋值规则进行转换。例如实参值同类型数值的赋值规则进行转换。例如实参值a为为3.5,而形参,而形参x为整型,则将为整型,则将实数实数3.5转换成整数转换成整数3,然后送到形参,然后送到形参b。字符型与整型可以互相通用。字符型与整型可以互相通用。e)在在C语言中,实参向形参的数据传递是语言中,实参向形参的数据传递是“值传递值传递”,单向传递单向传递,只由实参传给,只由实参传给形参,而不能由形参传回来给实参。在内存中,实参单元与形参单元是形参,而不能由形参传回来给实参。在内存中,实参单元与形参单元是不同的单元。不同的单元。6.3 6.3 函数的调用函数的调用26现在学习的是第26页,共134页711x:y:调用前:调用前:调用结束:调用结束:711x:y:例:例:#include main()void swap(int,int);int x=7,y=11;printf(x=%d,ty=%dn,x,y);printf(swapped:n);swap(x,y);printf(x=%d,ty=%dn,x,y);void swap(int a,int b)int temp;temp=a;a=b;b=temp;调用:调用:711a:b:711x:y:swap:711x:y:117a:b:temp27现在学习的是第27页,共134页 在调用函数时,给形参分配存储单元,并将实参对应的值传递在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保持并维持原给形参,调用结束后,形参单元被释放,实参单元仍保持并维持原值。因此,在执行一个被调用函数时,形参的值如果发生改变,并值。因此,在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数的实参的值。不会改变主调函数的实参的值。6.3 6.3 函数的调用函数的调用28现在学习的是第28页,共134页6.3 6.3 函数的调用函数的调用按函数在程序中出现的位置来分,可以有以下按函数在程序中出现的位置来分,可以有以下3 3种函数种函数调用的方式。调用的方式。1.函数语句函数语句 把函数调用作为一个语句。这时可以不要求函数带来返回把函数调用作为一个语句。这时可以不要求函数带来返回值,只要求函数完成一定的操作。值,只要求函数完成一定的操作。29现在学习的是第29页,共134页6.3 6.3 函数的调用函数的调用2 22 2a ax x3 33 3b by y2 21010a ax x3 31515b by y图图 6-3 6-3 参数值传递参数值传递图图 6-4 6-4 实参值不变实参值不变30现在学习的是第30页,共134页2.函数表达式函数表达式 函数出现在一个表达式中,这种表达式称为函数表达式。这是函数出现在一个表达式中,这种表达式称为函数表达式。这是要求函数带回一个确定的值以确定参加表达式的运算。例如:要求函数带回一个确定的值以确定参加表达式的运算。例如:C=2*max(a,b);函数函数max是表达式的一部分,它的值乘是表达式的一部分,它的值乘2再赋给再赋给c。6.3 6.3 函数的调用函数的调用31现在学习的是第31页,共134页3.3.函数参数函数参数函数调用作为一个函数的实参。例如:函数调用作为一个函数的实参。例如:m=max(a,max(b,c);m=max(a,max(b,c);其中其中max(b,c)max(b,c)是一次函数调用,它的值作为是一次函数调用,它的值作为maxmax另一次调用的另一次调用的实参。实参。m m的值是的值是a a、b b、c c三者中的最大者。三者中的最大者。又如:又如:printf(“%d”,max(a,b);printf(“%d”,max(a,b);把把max(a,b)max(a,b)作为作为printfprintf函数的一个函数。函数的一个函数。函数调用作为函数的参数,实质上也是函数表达式形式调用的一函数调用作为函数的参数,实质上也是函数表达式形式调用的一种,因为函数的参数本来就要求是表达式形式。种,因为函数的参数本来就要求是表达式形式。6.3 6.3 函数的调用函数的调用32现在学习的是第32页,共134页6.3 6.3 函数的调用函数的调用 在一个函数中调用另一个函数(即被调用函数)需要具备的在一个函数中调用另一个函数(即被调用函数)需要具备的条件如下:条件如下:1.1.首先被调用的函数必须是已经存在的函数(库函数或自定义函首先被调用的函数必须是已经存在的函数(库函数或自定义函数)。数)。33现在学习的是第33页,共134页6.3 6.3 函数的调用函数的调用2.2.如果使用库函数,还应该在文本开头用如果使用库函数,还应该在文本开头用#include#include命令将调用有命令将调用有关库函数时所需用到的信息(这些信息是一些常量和函数原型)关库函数时所需用到的信息(这些信息是一些常量和函数原型)“包含包含”到本文件中来,否则函数将不能正常地得到调用。到本文件中来,否则函数将不能正常地得到调用。例如,前面经常用到过:例如,前面经常用到过:#include#include 其中其中“stdio.h”stdio.h”是一个是一个“头文件头文件”。在。在stdio.hstdio.h文件中包含了输文件中包含了输入输出库函数所用到的一些宏定义信息。如果不包含入输出库函数所用到的一些宏定义信息。如果不包含“stdio.h”stdio.h”文件中的信息,就无法正常使用输入输出库中的函文件中的信息,就无法正常使用输入输出库中的函数。同样,使用数学库中的函数,应该用数。同样,使用数学库中的函数,应该用#include#include。其。其中,中,.h.h是头文件所用的后缀,标志头文件(是头文件所用的后缀,标志头文件(head filehead file)。)。34现在学习的是第34页,共134页6.3 6.3 函数的调用函数的调用3.3.如果使用用户自定义的函数,则如果该函数被定义的位如果使用用户自定义的函数,则如果该函数被定义的位置在调用它的函数(即主调函数)的置在调用它的函数(即主调函数)的后面后面(在同一文件中),(在同一文件中),应该在主调函数中对被调函数作应该在主调函数中对被调函数作声明声明。如果被调用函数的定义出。如果被调用函数的定义出现在主调函数之前,可以不必加以声明。现在主调函数之前,可以不必加以声明。35现在学习的是第35页,共134页 “声明声明”(declarationdeclaration)的作用)的作用:把函数名、函数参把函数名、函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。用时,编译系统能正确识别函数并检查调用是否合法。6.3 6.3 函数的调用函数的调用36现在学习的是第36页,共134页#include void main()float add(float x,float y);/*对被调用函数对被调用函数add的声明的声明*/float a,b,c;scanf(%f,%f,&a,&b);c=add(a,b);printf(sum is%fn,c);float add(float x,float y)/*函数首部函数首部*/float z;/*函数体函数体*/z=x+y;return(z);运行情况如下:运行情况如下:3.63.6,6.56.5sum is 10.100000sum is 10.1000006.3 6.3 函数的调用函数的调用例例6-5 6-5 编制子函数实现求两个单精度实数的和,编制子函数实现求两个单精度实数的和,mainmain函数调用该函数的时候要先声明。函数调用该函数的时候要先声明。37现在学习的是第37页,共134页6.3 6.3 函数的调用函数的调用函数的原型的一般形式有两种,分别为函数的原型的一般形式有两种,分别为:(1)(1)函数类型函数类型 函数名(参数类型函数名(参数类型1 1,参数类型,参数类型2 2,参数类型,参数类型n n););(2)(2)函数类型函数类型 函数名(参数类型函数名(参数类型1 1 参数名参数名1 1,参数类型,参数类型2 2 参数名参数名2 2,参数类型参数类型n n 参数名参数名n n););38现在学习的是第38页,共134页 注意:注意:对函数的对函数的“定义定义”和和“声明声明”不是一回事。不是一回事。“定义定义”是指对函数功能的确立,包括指定函数是指对函数功能的确立,包括指定函数名,函数值类型、形参及其类型、函数体等,它名,函数值类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位;而是一个完整的、独立的函数单位;而“声明声明”则则是把函数的名字、函数类型以及形参的类型、个是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用函数时系统数和顺序通知编译系统,以便在调用函数时系统按此进行对照检查。按此进行对照检查。39现在学习的是第39页,共134页函数调用机制(参数及其传递方式)函数调用机制(参数及其传递方式)l实际参数:调用函数时函数名后面括号中的表达式实际参数:调用函数时函数名后面括号中的表达式;l形式参数:定义函数时函数名后面括号中的变量名形式参数:定义函数时函数名后面括号中的变量名.c=add(a,b);(main 函数)函数)(add 函数)函数)add(int x,int y)float z;z=x+y;return(z);main()float add(float x,float y);float a,b,c;scanf(%f,%f,&a,&b);c=add(a,b);printf(sum is%fn,c);float add(float x,float y)float z;z=x+y;return(z);实参实参形参形参6.3 6.3 函数的调用函数的调用40现在学习的是第40页,共134页实参必须有确定的值实参必须有确定的值形参必须指定类型形参必须指定类型形参与实参形参与实参类型一致类型一致,个数相同个数相同若形参与实参类型不一致,自动按形参若形参与实参类型不一致,自动按形参类型转换类型转换函数调用转换函数调用转换形参在函数被调用前不占内存形参在函数被调用前不占内存;函数调用函数调用时为形参分配内存;调用结束,内存释放时为形参分配内存;调用结束,内存释放,实参单元仍保留并维持原值。也就是说,形实参单元仍保留并维持原值。也就是说,形参与实参占用参与实参占用不同不同的内存单元的内存单元单向单向传递传递值传递值传递6.3 6.3 函数的调用函数的调用41现在学习的是第41页,共134页12a调用前调用前a0a112a调用调用a0a112xy21xy交换交换12a返回返回#include void swap(int x,int y)int z;z=x;x=y;y=z;main()int a2=1,2;swap(a0,a1);printf(a0=%dna1=%dn,a0,a1);值值传传递递 数组元素数组元素与与数组名数组名 作函数参数比较:作函数参数比较:(1)数组元素作参数)数组元素作参数42现在学习的是第42页,共134页12a调用前调用前12ax调用调用21ax交换交换21a返回返回#include void swap(int x)int z;z=x0;x0=x1;x1=z;main()int a2=1,2;swap(a);printf(a0=%dna1=%dn,a0,a1);地址地址传递传递 数组元素数组元素与与数组名数组名 作函数参数比较:作函数参数比较:(2)数组名作参数)数组名作参数43现在学习的是第43页,共134页 1 1.用数组名作函数实参用数组名作函数实参,应该在主调函数和被调用函数应该在主调函数和被调用函数两方两方分别定分别定义数组,此时形参应当用数组名或指针变量。义数组,此时形参应当用数组名或指针变量。2 2.实参与形参类型必须一致(如上例均为实参与形参类型必须一致(如上例均为intint型)。型)。3.3.实参与形参数组大小可以一致也可以不一致,实参与形参数组大小可以一致也可以不一致,C C语言编译对形语言编译对形参数组的大小参数组的大小不做检查不做检查,指定大小不起作用。,指定大小不起作用。4 4.数组名作参数时,不是数组名作参数时,不是“值传递值传递”,而是把实参数组的而是把实参数组的起始地址起始地址传递给形参数组,这样两个数组传递给形参数组,这样两个数组共占同一段内存共占同一段内存,这与变量做函,这与变量做函数参数的情况不相同。上例中数参数的情况不相同。上例中anan与与xnxn指向的是同一单元,具有指向的是同一单元,具有相同的值。相同的值。44现在学习的是第44页,共134页用多维数组作函数参数用多维数组作函数参数 多维数组元素可以作为实参,这点与前述相同。多维数组元素可以作为实参,这点与前述相同。可以用多维数组名作为实参和形参,在被调用函数中对形参数组定义可以用多维数组名作为实参和形参,在被调用函数中对形参数组定义时可以指定每一维的大小,也可以省略第一维的大小说明。如时可以指定每一维的大小,也可以省略第一维的大小说明。如:int array310 int array310;或或 int array 10int array 10;二者都合法而且等价。二者都合法而且等价。C C编译系统不检查第一维的大小,但是编译系统不检查第一维的大小,但是不不能把第二维以及其它高维的大小说明省略能把第二维以及其它高维的大小说明省略。如下面是不合法的:。如下面是不合法的:int array3 int array3;int array int array ;45现在学习的是第45页,共134页 因为从实参传送来的是因为从实参传送来的是数组起始地址数组起始地址,在内存中按数组排,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列。不能只中不说明列数,则系统无法决定应为多少行多少列。不能只指定第一维而省略第二维。指定第一维而省略第二维。实参数组可以大于形参数组。例如,实参数组定义为实参数组可以大于形参数组。例如,实参数组定义为 int int scorescore5 51010;而形参数组定义为而形参数组定义为 int arrayint array3 31010;这时形参数组只取实参数组的这时形参数组只取实参数组的一部分一部分,其余部分不起作用。,其余部分不起作用。可以从可以从“传递地址传递地址”这一特点出发理解该问题。这一特点出发理解该问题。46现在学习的是第46页,共134页 例例 有一个有一个3 34 4的矩阵,求其中的最大元素。的矩阵,求其中的最大元素。#include#include void main void main()()int max_value int max_value(int array 4int array 4);int a34=1,3,5,7 int a34=1,3,5,7,2,4,6,8,15,17,34,122,4,6,8,15,17,34,12;printfprintf(”max value is%d max value is%d n”n”,max_valuemax_value(a a););int max_value int max_value(int array 4int array 4)int i,j,k,max int i,j,k,max;max=array00max=array00;for(i=0 for(i=0;i3i3;i+i+)forfor(j=0j=0;j4jmaxarrayijmax)max=arrayij;max=arrayij;return return(maxmax););47现在学习的是第47页,共134页函数调用的内部过程:函数调用的内部过程:函数调用的内部过程:函数调用的内部过程:出现函数调用时,主调函数的执行过程暂时停止,在进行了必要的出现函数调用时,主调函数的执行过程暂时停止,在进行了必要的“现场现场”保存工作后,转去执行被调函数的代码,待被调函数执行保存工作后,转去执行被调函数的代码,待被调函数执行完毕返回后,首先恢复刚才保存的完毕返回后,首先恢复刚才保存的“现场现场”,然后继续主调函数,然后继续主调函数的执行。的执行。主调函数主调函数知知 识识 回回 顾顾被调函数开始被调函数开始被调函数开始被调函数开始被调函数结束被调函数结束被调函数结束被调函数结束(传递参数传递参数传递参数传递参数)(返回函数值返回函数值返回函数值返回函数值)被调函数被调函数函数调用函数调用函数调用函数调用4848现在学习的是第48页,共134页6.3.2 函数的嵌套调用(nesting)C C语言函数的定义是平行的、独立的,语言函数的定义是平行的、独立的,函数定义不能嵌套函数定义不能嵌套。即:。即:在一个函数定义的函数体中,不能再定义另一个函数。在一个函数定义的函数体中,不能再定义另一个函数。C C语言语言函数的调用可以嵌套函数的调用可以嵌套。即:在调用一个函数的过程中,又可。即:在调用一个函数的过程中,又可以调用另一个函数。以调用另一个函数。main函数函数a函数函数调用函数调用函数a调用函数调用函数bb函数函数49现在学习的是第49页,共134页 上图表示两层嵌套(连上图表示两层嵌套(连mainmain函数共函数共3 3层函数),其执行过程是:层函数),其执行过程是:(1)(1)执行执行mainmain函数的开头部分;函数的开头部分;(2)(2)遇函数调用遇函数调用a a的操作语句,流程转去的操作语句,流程转去a a函数;函数;(3)(3)执行执行a a函数的开头部分;函数的开头部分;(4)(4)遇调用遇调用b b函数的操作语句,流程转去函数函数的操作语句,流程转去函数b;b;(5)(5)执行执行b b函数,如果再无其它嵌套的函数,则完成函数,如果再无其它嵌套的函数,则完成b b函数的全部操作;函数的全部操作;(6)(6)返回调用返回调用b b函数处,即返回函数处,即返回a a函数;函数;(7)(7)继续执行继续执行a a函数中尚未执行的部分,直到函数中尚未执行的部分,直到a a函数结束;函数结束;(8)(8)返回返回mainmain函数中调用函数中调用a a函数处;函数处;(9)(9)继续执行继续执行mainmain函数的剩余部分直到结束。函数的剩余部分直到结束。50现在学习的是第50页,共134页main()aia