资源预览内容
第1页 / 共210页
第2页 / 共210页
第3页 / 共210页
第4页 / 共210页
第5页 / 共210页
第6页 / 共210页
第7页 / 共210页
第8页 / 共210页
第9页 / 共210页
第10页 / 共210页
亲,该文档总共210页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
在结构化程序设计中,函数是将任务进行模块划分的基 本单位。一个函数实现一项功能。在面向对象程序设计中,函数是对数据的一项操作,也 是实现一项功能。第三章 函 数 要掌握函数的使用,必须理解函数调用时的内部实现机 制,以及与此相关的内存分配机制、变量生命期和作用域。本章还将介绍关于函数重载的概念,介绍递归算法 、内联函数、默认参数函数以及多文件组织、编译预处 理、工程文件的概念和运行库函数。第三章 函 数 3.1 函数的定义与调用 3. 5 作用域与标识符的可见性 3.4 函数调用机制 3.3 全局变量和局部变量 3.2 函数的参数传递,返回值及函数声明 3.10 编译预处理 3.9 头文件与多文件结构 3.6 存储类型与标识符的生命期 3.8 函数的一些高级议题 3.7 函数的递归调用 3.1 函数的定义与调用3.1.1 函数概述3.1.2 函数的定义3.1.3 函数的调用 3.1.1 函数概述函数是C+程序的基本组成模块。通过函数,可以把一个复杂任务分解成为若干 个易于解决的小任务。充分体现逐步细化的设计思想 。组成C+程序的若干函数中,有一个称为main() (Winmain())函数,是程序执行的入口,它可以调 用其他函数,但不可以被调用。而其他一般函数既可 以调用也可以被调用。函数概念的引入:入口函数:3.1.1 函数概述main ( )fun2( )fun1( )fun3( )funa( )funb( )func( )图3.1 函数调用层次关系3.1.1 函数概述3.1.1 结束库函数和自定义函数:库函数或标准函数,是由编译系统预定义的, 如一些常用的数学计算函数、字符串处理函数、图 形处理函数、标准输入输出函数等。库函数都按功能分类,集中说明在不同的头文 件中。用户只需在自己的程序中包含某个头文件, 就可直接使用该文件中定义的函数。用户根据需要将某个具有相对独立功能的程序 定义为函数,称自定义函数。3.1.2 函数的定义无参函数定义格式为:数据类型函数名(void)函数体说明:数据类型指函数返回值类型,可以是任一种数据类型, 默认为返回整型值(但新标准要求写明,不用默认方式)。 没有返回值应将返回值类型定义为void。函数名采用合法标识符表示。对无参函数,参数括号中的void通常省略,但括号不能 省略。函数体由一系列语句组成。函数体可以为空,称为空函 数。 1 1 无参函数无参函数3.1.2 函数的定义例: 打印一个表头 void TableHead ( ) cout=b?a:b); 有参函数的参数表中列出所有形式参数的类型和参数名 称。各参数即使类型相同也必须分别加以说明。形式参数简称形参,只能是变量名,不允许是常量或表 达式。 问题:定义函数时究竟哪些变量应当作为函数的参数?哪些 应当定义在函数体内? 原则:函数在使用时被看成 “黑匣子”,除了输入输出外, 其他部分可不必关心。从函数的定义看出,函数头正是用来反 映函数的功能和使用接口,它所定义的是“做什么”。即明确 了“黑匣子”的输入输出部分,输出就是函数的返回值,输入 就是参数。因此,只有那些功能上起自变量作用的变量才必须 作为参数定义在参数表中;函数体中具体描述“如何做”,因 此除参数之外的为实现算法所需用的变量应当定义在函数体内 。C+中不允许函数的嵌套定义,即在一个函数中定义另一 个函数。提示3.1.3 函数的调用 函数调用:所谓函数调用,就是使程序转去执行函数体。在C+中,除了主函数外,其他任何函数都不能单独作为 程序运行。任何函数功能的实现都是通过被主函数直接或间 接调用进行的。无参函数的调用格式:函数名( )有参函数的调用格式:函数名(实际参数表) 其中实际参数简称实参,用来将实际参数的值传递给形参, 因此可以是常量、具有值的变量或表达式。【例3.1】 输入两个实数,输出其中较大的数3.2 函数的参数传递、返回值及 函数声明321 函数的参数传递及传值调用 323 函数声明322 函数返回值 参数传递:函数调用首先要进行参数传递,参数传递的方向是由实 参传递给形参。传递过程是,先计算实参表达式的值,再将该值传递给 对应的形参变量。一般情况下,实参和形参的个数和排列顺 序应一一对应,并且对应参数应类型匹配(赋值兼容),即 实参的类型可以转化为形参类型。而对应参数的参数名则不 要求相同。3.2.1 函数的参数传递及传值调用 传值调用和引用调用: 按照参数形式的不同,C+有两种调用方式:传值调用和引 用调用。传值调用传递的是实参的值,本章介绍传值调用。3.2.1 函数的参数传递及传值调用 传值调用: 将实参的值复制给形参,在函数中参加运算的 是形参,而实参不会发生任何改变。传值调用 起了一种隔离作用。【例3.2】 实参和形参对应关系的示例。注意:【例1.3】中调用函数strcpy(s3, s2),却实现了字符数 组s2的内容复制到字符数组s3中。这是因为数组名实际 上代表存储数组的内存的首地址,复制给形参的是实参数 组的首地址,结果参加运算的是实参数组。数组作为参数 ,定义时形参用数组名加一对方括号,调用时实参只用数 组名 3.2.2 函数返回值return语句的格式:return 表达式;函数的计算结果通过该语句传递回主调函数。【例3.3】设计函数,根据三角形的三边长求面积。如 果不能构成三角形,给出提示信息。 分析:函数为计算三角形面积,一般三角形返回面积值, 若不能构成三角形则返回-1。设计一个主函数完成函数测 试。根据返回值情况输出相应结果。3.2.2 函数返回值函数可以有返回值,也可以没有返回值。对于 没有返回值的函数,功能只是完成一定操作,应将 返回值类型定义为void ,函数体内可以没有 return语句,当需要在程序指定位置退出时,可以 在该处放置一个:return ;讨论:3.2.2 结束3.2.3 函数声明函数声明是一条以分号结束的语句: 函数返回值类型函数名 (形参表); 语法上对程序文件中函数的排列次序要求满足先定义后 使用。但从结构化程序设计的角度,通常是先调用后定义。 使用函数声明,则既符合由粗到精的思维方式,又满足了语 法要求。其中形参表可以逐个列出每个参数的类型和参数名, 也可以列出每个形参的类型,参数名可省略,各形参之间 以逗号分隔。函数声明和所定义的函数必须在返回值类型 、函数名、形参个数和类型及次序等方面完全对应一致, 否则将导致编译错误。 函数声明的引入:函数声明的格式:下面是一个使用结构化程序设计思想开发的企业管理 报表程序的框架。它使用了函数声明。 void menu_print(); void account_report(); void engineering_report(); void marketing_report(); int main()int choice;do menu_print(); cinchoice;while(choice=4);switch(choice)case 1: account_report(); break;case 2: engineering_report(); break;case 3: marketing_report(); break; return 0;void menu_print() cout=0 其中的iostream是在标准名字空间域std中定义的头文件。对应 的传统方式的文件名为,头文件以“.h”为后缀。系统定义的头文件中定义了一些常用的公用标识符和函数 ,用户只要将头文件包含进自己的文件,就可使头文件中定义 的标识符在用户文件中变得可见,也就可以直接使用头文件中 定义的标识符和函数。 3.9.1 头文件自定义头文件: 除了系统定义的头文件外,用户还可以自定义头文件 。对于具有外部存储类型的标识符,可以在其他任何 一个源程序文件中经声明后引用,因此用户完全可以 将一些具有外部存储类型的标识符的声明放在一个头 文件中。具体地说,头文件中可以包括:用户构造的 数据类型(如枚举类型),外部变量,外部函数、常 量和内联函数等具有一定通用性或常用的量,而一般 性的变量和函数定义不宜放在头文件中。3.9.2 多文件结构 在开发较大程序时,通常将其分解为多个源程序文件 ,每个较小的程序用一个源程序文件建立。程序经过建立 、编译、连接,成为一个完整的可执行程序。多文件结构 通过工程进行管理,在工程中建立若干用户定义的头文件 .h和源程序文件.cpp。头文件中定义用户自定义的数据类 型,所有的程序实现则放在不同的源程序文件中。编译时 每个源程序文件单独编译,如果源程序文件中有编译预处 理指令,则首先经过编译预处理生成临时文件存放在内存 ,之后对临时文件进行编译生成目标文件.obj,编译后临 时文件撤销。所有的目标文件经连接器连接最终生成一个 完整的可执行文件.exe。图3.11是一个多文件系统的开发过程。3.9.2 多文件结构 编译预编译编译预编译 预编译编译图3.11 C+程序开发过程file1.hfile1.cppfile2.hfile2.cppfilen.hfilen.cpp临时文件1临时文件2临时文件nfile1.objfile2.objfilen.objFilename. exe.lib C+标准类库连接运行3.10 编译预处理(选读) 3.10.1 宏定义指令 3.10.2 文件包含指令 3.10.3 条件编译指令 3.10.1 宏定义指令1 不带参宏定义 用来产生与一个字符串对应的常量字符串,格式为: #define 宏名 常量串 预处理后文件中凡出现该字符串处均用其对应的常量 串代替。替换过程称为宏替换或宏展开。例如,如果 使用指令 #define PI 3.1415926 则程序中可以使用标识符PI,编译预处理后产生一个 中间文件,文件中所有PI被替换为3.1415926。 宏替换只是字符串和标识符之间的简单替换,预处理 本身不做任何数据类型和合法性检查,也不分配内存 单元。3.10.1 宏定义指令2 带参数的宏定义 带参宏定义的形式很象定义一个函数,格式为: #define 宏名 ( 形参表 ) 表达式串 例如作如下宏定义: #define S(a,b) (a)*(b)/2 程序中可使用S(a,b),预处理后产生中间文件,其中S(a,b)被 替换成(a)*(b)/2。注意,宏定义时形参通常要用括号括起来 ,否则容易导致逻辑错误。例如,如果定义: #define S(a,b) a*b/2 那么程序中的S(3+5,4+2)就会被宏展开为3+5*4+2/2,不 符合定义的真正的意图。 带参宏定义形式上象定义函数,但它与函数的本质不同,宏定 义仍然只是产生字符串替代,不存在分配内存和参数传递。 3.10.2 文件包含指令文件包含用#include指令,预处理后将指令中指明的源程序 文件嵌入到当前源程序文件的指令位置处。格式为: #include 或 #include 文件名 第一种方式称为标准方式,预处理器将在include子目录下搜 索由文件名所指明的文件。这种方式适用于嵌入C+提供的 头文件,因为这些头文件一般都存在C+系统目录的 include子目录下。而第二种方式编译器将首先在当前文件所 在目录下搜索,如果找不到再按标准方式搜索。这种方式适 用于嵌入用户自己建立的头文件。一个被包含的头文件中还可以有#include指令, 即include指令可以嵌套,但是,如果同一个头文 件在同一个源程序文件中被重复包含,就会出现标 识符重复定义的错误。例如:头文件f2.h中包含了 f1.h,如果文件f3.cpp中既
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号