函数和编译预处理.ppt

上传人:小飞机 文档编号:6221442 上传时间:2023-10-06 格式:PPT 页数:47 大小:263.99KB
返回 下载 相关 举报
函数和编译预处理.ppt_第1页
第1页 / 共47页
函数和编译预处理.ppt_第2页
第2页 / 共47页
函数和编译预处理.ppt_第3页
第3页 / 共47页
函数和编译预处理.ppt_第4页
第4页 / 共47页
函数和编译预处理.ppt_第5页
第5页 / 共47页
点击查看更多>>
资源描述

《函数和编译预处理.ppt》由会员分享,可在线阅读,更多相关《函数和编译预处理.ppt(47页珍藏版)》请在三一办公上搜索。

1、第5章,函数和编译预处理,本章主要内容,5.1 函数的基本概念5.2 函 数 定 义5.3 函 数 调 用5.4 函数的参数传递和函数的返回值5.5 函 数 声 明5.6 带默认形参值的函数5.7 内 联 函 数5.8 函数的嵌套和递归调用5.9 作用域和存储类型5.10 函数的重载5.11 编译预处理5.12 程序的多文件组织,5.1 函数的基本概念,在C+语言中,从不同的角度对函数分类如下。1.库函数和用户定义函数 从函数定义的角度看,函数可分为库函数和用户自定义函数两种。(1)库函数:C+编译系统、操作系统或其他系统为方便用户程序设计而预定义的函数,只需在程序前包含有该函数原型的头文件即

2、可在程序中直接调用。(2)用户自定义函数:由用户根据自己的需要,将完成某一相对独立功能的程序定义为一个函数,称为用户自定义函数。,5.1 函数的基本概念,2.有返回值函数和无返回值函数 C+语言的函数兼有其他语言中的函数和过程两种功能,从这个角度看,又可把函数分为有返回值函数和无返回值函数两种。(1)有返回值函数:此类函数被调用执行完后将向调用者返回一个执行结果,称为函数返回值。(2)无返回值函数:此类函数用于完成某项特定的处理任务,执行完成后不向调用者返回函数值。,5.1 函数的基本概念,3.无参函数和有参函数 从主调函数和被调函数之间数据传送的角度看又可分为无参函数和有参函数两种。(1)无

3、参函数:函数定义、函数说明及函数调用中均不带参数。主调函数和被调函数之间不进行参数传送。(2)有参函数:也称为带参函数。在函数定义及函数说明时都有参数,称为形式参数(简称为形参)。,5.2 函 数 定 义,5.2.1 无参函数的定义5.2.2 有参函数的定义5.2.3 函数定义的注意点,5.2.1 无参函数的定义,定义无参函数的一般格式为:(void)/函数头 其中,type为函数返回值的类型,可以是标准数据类型或导出的数据类型。函数名必须符合标识符构成的规则。通常,函数名应能反映函数的功能。为一个复合语句,用于实现相应函数的功能。当函数仅完成某种固定操作时,可将函数定义为无参函数。在很多情况

4、下都不要求无参函数有返回值,此时函数类型符可以写为void。,5.2.2 有参函数的定义,定义有参函数的一般格式为:()有参函数比无参函数多了形式参数列表。由一个或多个形参说明构成,每个形参说明的格式为:其中的是形式参数的名,用标识符表示,其格式和定义与变量相同。作为函数体的复合语句中可以包含return语句,当函数体执行到return语句时,函数立即返回到调用者,return语句的格式为:return 或 return;,5.2.3 函数定义的注意点,在定义一个函数时要注意以下几个方面:(1)确定该函数所要实现的功能,使用自然语言(汉语等)或数学的方法描述出实现该功能的算法和步骤。(2)一个

5、函数可有多个形参。(3)确定函数功能的算法是否有结果需要返回给调用者。(4)函数名最好能够让调用者看到函数名就能够明白函数的功能。(5)空函数:函数体为空的函数,花括号不可省。(6)函数定义时,函数体内不能包含其他函数的定义。,5.3 函 数 调 用,5.3.1 函数调用的一般形式5.3.2 函数调用的方式5.3.3 函数调用的注意点,5.3.1 函数调用的一般形式,调用函数的一般格式为:()其中,是已定义的函数的名字;由零个、一个或多个实际参数(用逗号分割)构成。每个实际参数(简称实参)都是一个表达式,它们的个数以及对应位置的类型应该和定义该函数时指定的形参类型相同,如果类型不同,则系统将利

6、用类型转换,将实参的值转换成形参类型,然后赋给形参。形参和实参的个数应该相等。,5.3.2 函数调用的方式,在C+中,有3种函数调用方式。1.函数语句 函数调用的一般形式加上分号即构成函数语句。2.函数表达式 函数作为表达式中的一项出现在表达式中,以函数返回值参与表达式的运算。这种方式要求函数是有返回值的。3.函数实参 函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作为实参进行传送。例5-1 求任意两个实数和的函数,5.3.3 函数调用的注意点,(1)函数调用时,系统为形参分配相应的存储单元,用于接收实参传递的数据。(2)若函数的形参为普通变量(不是指针变量和引用变量),则调

7、用该函数时,实参给形参赋值,这种参数传递方式称为值传递或传值。(3)传值调用时,实参的求值顺序因编译系统而异,有的从右向左,有的从左向右。(4)传值调用的优点是,函数调用对其外界的变量无影响,最多只能用return返回一个值,函数的独立性强。例5-2 函数值传递调用,5.4 函数的参数传递和函数的返回值,5.4.1 函数的形式参数和实际参数5.4.2 函数的返回值,5.4.1 函数的形式参数和实际参数,形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传

8、送给被调函数的形参从而实现主调函数向被调函数的数据传送。,5.4.1 函数的形式参数和实际参数,函数的形参和实参具有以下几个特点。(1)当被调函数有参数时,主调函数和被调函数之间通过形参实现数据传递。(2)定义函数时指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,只有在发生函数调用时,形参才被分配内存单元。在调用结束后,形参所占的内存单元被释放。(3)函数调用时实参的类型应与形参的类型一一对应。(4)实参应有确定值,可为常量、变量或表达式。(5)在定义函数时,必须在函数首部指定形参的类型。,5.4.2 函数的返回值,函数的返回值是通过函数中的return语句获得的,由被调函数计算处

9、理后向主调函数返回的计算结果,最多只能一个。无返回值的函数其返回值类型应说明为void类型,否则将返回一个不确定的值。,5.4.2 函数的返回值,关于函数的返回值有以下一些说明。(1)在函数中允许有多个return语句,但每次调用只能有一个return 语句被执行,因此只能返回一个函数值。(2)return 语句后面的括号可以要,也可以不要,如“return z;”与“return(z);”等价。(3)在执行被调函数时,遇到return语句就结束函数的执行,返回到主调函数。(4)若函数有多个返回分支,则应保证每个分支均有确定的返回值,否则可能出现逻辑错误。,5.5 函 数 声 明,函数声明由函

10、数返回类型、函数名和形参列表组成。形参列表必须包括形参类型,但不必对形参命名。函数声明一般形式为:();函数声明与函数定义在返回类型、函数名和参数类型方面必须一致;函数声明是语句,必须以分号“;”结束,而函数定义时的头部之后不能有分号。例5-3 函数声明,5.5 函 数 声 明,以下是有关函数声明的几点说明。(1)一个函数的函数原型声明应出现在该函数调用之前。(2)如果函数定义在函数调用语句之前,则不必进行函数原型声明。(3)在函数声明中,可以只列出形参的类型。(4)函数声明的作用是给编译器提供关于函数的信息,使得编译器能够对函数调用的合法性进行检查,并产生函数调用的正确代码。,5.6 带默认

11、形参值的函数,在C+中,允许在定义或声明函数时,为函数的某些参数指定默认值。当调用这些函数时,若没有提供相应的实参,则相应的形参采用指定的默认值。在指定函数参数的默认值时,应该注意下面几点:(1)有默认形参值的形参应该处于形参表的右部。(2)形参的默认值可以是常量表达式,即表达式中用到的量必须是常量。例5-4 带默认形参值的函数 例5-5 带有多个默认形参值的函数 例5-6 函数声明中指定形参默认值,5.7 内 联 函 数,函数定义时,在函数的返回类型之前加上一个关键字inline,指明将这函数定义为内联函数,其作用是建议编译器把该函数的函数体代码展开到调用处。内联函数的实质是用空间换取时间,

12、即占用更多的存储空间而减少执行时间。内联函数机制:不是在调用时发生转移,而是在编译时将函数体嵌入到每个内联函数调用处。,5.7 内 联 函 数,在使用内联函数时,需要注意以下几点:。(1)编译器对内联函数的限制。(2)功能简单、代码短小(不含循环、switch和复杂嵌套的if语句)、运行时间极短、调用频繁的函数应定义成内联的。(3)程序中多次调用同一内联函数时,增加了程序本身占用的存储空间;而内联函数仅调用一次时,并不增加程序占用的存储空间。,5.8 函数的嵌套和递归调用,5.8.1 函数的嵌套调用5.8.2 函数的递归调用,5.8.1 函数的嵌套调用,函数之间都是平等的、平行的,即不允许函数

13、的嵌套定义。但允许在一个函数的定义中调用另一个函数,即允许函数的嵌套调用。嵌套的函数调用返回时将根据嵌套层次逐层返回,如图5.2所示。例5-7 函数的嵌套调用,图5.2 嵌套调用及返回,5.8.2 函数的递归调用,如果一个函数在其函数体中直接或者间接地调用了自己,则该函数称为递归函数。在定义递归函数时,一定要对两种情况给出描述:(1)递归条件。指出何时进行递归调用。(2)结束条件。结束条件指出何时不需要递归调用。例5-8 求n阶勒让德多项式的值 例5-9 递归函数,5.8.2 函数的递归调用,递归法解决问题的关键有以下两点。(1)归纳问题的递归特征:将原问题转化为一个新问题,而这个新问题与原问

14、题有相同的解决方法。(2)分析和总结问题的递归求解结束条件:只有有限次递归才有实际意义。例5-10 递归函数 例5-11 河内塔问题求解(见书P.98),5.9 作用域和存储类型,5.9.1 作用域5.9.2 局部变量与全局变量5.9.3 动态与静态变量5.9.4 变量的存储类型,5.9.1 作用域,1.块作用域 块是用一对花括号“”括起来的部分程序。块作用域是指在一个块内说明的标识符,只能在变量定义处到块尾之间的区域中使用。在C+标准中规定如下:(1)局部更优先:内层标识符在其作用域内,将屏蔽其外层作用块的同名标识符。(2)在for语句中说明的循环控制变量具有块作用域,其作用域为包含for语

15、句的整个循环体。例5-12 块作用域 例5-13 同名变量的作用域,5.9.1 作用域,2.文件作用域 是指从函数外变量定义开始到文件结束(可用extern进行扩展)。3.函数原型作用域 在函数原型的参数表中说明的标识符所具有的作用域称为函数原型作用域。4.函数作用域 不允许在一个函数内用goto语句转移到另一个函数内的某一个语句去执行。,5.9.2 局部变量与全局变量,1.局部变量 在函数或块内定义的变量称为局部变量,具有块作用域。2.全局变量 定义在函数外的变量称为全局变量,具有文件作用域。即全局变量的作用域从变量定义位置开始到文件结束为止。3.全局变量的声明 可以在其它地方声明已定义的全

16、局变量,以达到在该处访问这个全局变量的目的。extern 例5-14 全局变量与局部变量 例5-15 全局变量声明 例5-16 全局变量声明的作用域,5.9.3 动态与静态变量,1.存储空间分类 一个程序在内存中占用的存储空间可以分为三个部分:(1)程序区:存放可执行的程序代码;(2)静态存储区:存放程序中定义的静态变量;(3)动态存储区:存放程序中定义的动态变量。2.动态变量 在程序执行过程中分配存储空间的变量称为动态变量。3.静态变量 在程序开始执行时系统就为变量分配存储空间,直到程序执行结束时,才收回为变量分配的存储空间,这种变量称为静态变量。,5.9.4 变量的存储类型,在C+中,变量

17、的存储类型分为四种:自动类型、寄存器类型、外部类型、静态类型。1.自动类型变量 在说明局部变量时,用关键字auto修饰的变量称为自动类型变量。例5-17 自动类型变量的初始化2.静态类型变量 用关键字static修饰的变量称为静态类型变量。例5-18 使用静态类型的局部变量 例5-19 限定全局变量的作用域,5.9.4 变量的存储类型,3.寄存器类型变量 在变量定义前加关键字register,该变量就是一个register变量。定义格式:register;4.外部类型变量 在说明全局变量时,用关键字extern修饰的全局变量称为外部变量。外部变量说明分为两种:(1)定义性说明:为该变量分配内存

18、并初始化。一个外部变量只能做一次定义性说明。其格式为:extern=;(2)声明性说明:只是扩展其作用域。例5-20 外部变量的使用,5.9.4 变量的存储类型,5.存储类型小结(1)基于变量访问的安全性以及内存利用效率等方面的考虑,在实际编程时,优先使用自动变量,严格限制使用静态变量和外部变量,基本不用寄存器变量。(2)不得不使用静态变量时,优先使用静态局部变量。(3)不得不使用全局变量时,优先使用静态全局变量。(4)不得不使用外部变量时,优先采用块作用域对外部变量的作用域做扩展。,5.10 函数的重载,1.重载函数的定义 C+规定:在同一作用域中,可以为多个不同的函数取相同的名字,此时,我

19、们称这些不同的函数重载了该名字。例5-21 重载求加法的函数add 定义重载函数时要注意以下几点。(1)定义的重载函数的形参必须不同,即:或者参数个数不同或者数据类型不同。(2)函数的返回值不能作为重载的依据。(3)重载函数虽然名字相同,但是仍然是不同的函数,彼此无关。,5.10 函数的重载,2.重载函数的绑定 把函数调用和重载函数集合中的一个函数相关联的过程称为绑定(binding,又称为联编)。(1)寻找一个严格的匹配(即每个实参类型都和形参类型完全相同。(2)通过内部转换寻求一个匹配。(3)通过用户定义的转换寻求一个匹配。(4)如果上述(1)、(2)、(3)匹配都失败,则该重载函数的调用

20、将失败。,5.11 编译预处理,5.11.1 包含文件5.11.2 不带参数的宏定义5.11.3 带参数的宏定义5.11.4 条件编译,5.11.1 包含文件,在一个源程序文件中的任一位置可以将另一个源程序文件的全部内容包含进来。include编译预处理指令实现这一功能。该编译预处理指令的格式为:#include 或#include 文件名#include:预处理器从系统目录中查找文件,如果找不到,则预处理器就报告错误。#include 文件名:预处理器从用户当前工作目录中开始查找文件,若未找到,则到系统目录中查找,若都未找到,则预处理器报告错误。#include指令的作用是:要求编译预处理程

21、序将指定“文件名”的文件内容替代该include指令行。,5.11.1 包含文件,对include文件包含指令的几点说明。(1)包含文件的扩展名推荐用“.h”(head的缩写)。(2)一个include命令只能指定一个被包含的文件。(3)在一个头文件中,可以利用#include指令包含另一个头文件。也就是说,头文件可以嵌套包含。(4)include命令可出现在程序中的任何位置,通常放在程序的开头。(5)为了便于文件包含,允许在文件名前加路径。,5.11.2 不带参数的宏定义,不带参数的宏定义的格式如下所示:#define 标识符替换文本其中#define 为预编译命令,“替换文本”为“标识符”

22、所代表的字符序列集合,可以为任意字符的组合。在程序代码被编译之前,编译系统自动将所有标识符出现的位置,被其代表的“替换文本”无条件的替换,然后再进行语法检查和编译。例5-22 使用无参数宏输出学生的人数,5.11.3 带参数的宏定义,带参数的宏定义有点类似于函数,在进行宏替换时,先进行参数替换,再进行宏替换。定义带参数宏的一般格式为:#define 宏(参数列表)替换文本 例5-23 multiply宏实现两个数的乘法,5.11.4 条件编译,条件编译通常有以下6种格式,其中,前面4种是针对宏名,后面两种针对给定条件的值。(1)#ifdef 宏名 程序#endif(2)#ifdef 宏名 程序

23、1#else 程序2#endif(3)#ifndef 宏名 程序#endif(4)#infdef 宏名 程序1#else 程序2#endif(5)#if 给定条件为真 程序#endif(6)#if 给定条件为真 程序1#else 程序2#endif,5.12 程序的多文件组织,5.12.1 内部函数和外部函数5.12.2 程序的多文件组织方法5.12.3 多文件组织的编译和连接,5.12.1 内部函数和外部函数,1.内部函数 如果一个函数只能被本文件中的其他函数调用,该函数就称为内部函数,定义内部函数时,在函数最左面加关键字static,表明该函数是一个内部函数。2.外部函数 如果一个函数可以

24、被其他源文件调用,该函数就称为外部函数,定义外部函数时,在函数最左面加关键字extern,表明该函数是一个外部函数。,5.12.2 程序的多文件组织方法,多文件组织程序具有便于代码的设计、调试以及重用、多人协同编写同一个程序等优势。可以将程序按功能(面向过程)或按类(面向对象)分成若干模块,再将每个模块的接口和实现分离,分别存于指定的头文件(“.h”)和实现文件(“.cpp”)中。头文件和实现文件都是文本文件。头文件就是模块的接口,通常包含模块中的全局类型定义、函数原型声明、全局常量和变量的定义、模板和命名空间的定义、编译预处理命令、注释等。实现文件是模块的实现。包含本模块的头文件、函数定义、类的成员函数定义、编译预处理命令、注释等。,5.12.3 多文件组织的编译和连接,编译、链接一个由多文件组成的程序,通常有3种方式:(1)包含命令方式。在定义main函数的文件中将组成同一程序的其他文件用包含命令包含进来,由编译程序对这些源程序文件一起编译,并链接成一个可执行的文件。(2)单独编译方式。将各个源程序文件单独编译成目标程序,然后用操作系统或编译器提供的链接程序将这些目标程序文件链接成一个可以执行的程序文件。(3)工程(或项目)文件。先建立一个工程文件,将组成一个程序的所有文件都加到工程(或项目)文件中,由编译器自动完成这些文件的编译和链接。,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号