【文档说明】C++程序设计学习培训(课件)-C++函数.ppt,共(31)页,510.500 KB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-44706.html
以下为本文档部分文字说明:
C++函数C++函数函数的定义4.1函数存在的意义为什么要使用的函数4.2函数重载43.3C++函数变量的引用4.5函数的默认参数4.4C++函数的递归调用4.6内嵌函数4.7函数和变量的作用域4.8学习目标本章主要介绍函数定义和函数调用格式、函数原形和头文件的作用、函数
调用中的参数传递机制、函数重载及函数和变量的作用域以及函数模板的概念及定义方法。通过对本章的学习,同学们能够掌握函数的有关使用:1.函数的定义方法和调用方法;2.函数的类型和返回值;3.形式参数与实在参数,参数值的传递;4.变量的作用域、生
存周期和存储类别(自动、静态、寄存器,外部);5.递归函数;6.内联函数;7.带有缺省参数值的函数。4.1函数的定义在程序设计中,我们也会有各种各样的“工具”。你告诉比较大小的“工具”两个不相等的数,这个“
工具”能够告诉你哪个数大;你告诉求正弦值的“工具”一个弧度,这个工具能够求出这个弧度对应的正弦值等等……这些工具的名字就是函数(Function)。注意:在程序设计中的函数和数学中的函数有相似的地方,但是它们却完全是两码事,请不要将两者等同起来。函
数和工具的性质是一样的。如果有一个现成求正弦值的函数,我们就不必自己去“造”一个这样的函数。求正弦值的函数是可以多次使用的,并且可以求出任意实数的正弦值(合适的情况下),但是它却求不出一个虚数的正弦值(
不合适的情况下)。4.1.1如何定义和使用函数有时候我们会知道一个工具有什么功能,但是却因为对其陌生而不会使用,这时候要使用它可能会发生一些困难。除了自己有空去摸索一下以外,最有效的办法就是去看说明书了。说明书里会告诉你什么东西放在什么
位置上,使用了以后会产生什么效果之类的。同工具一样,每个函数也有其自己的说明书,告诉用户如何调用(就是使用的意思)这个函数。这份说明书就称为这个函数的原型。4.1.2系统函数我们经常在程序的一开始就写#include某个头文件。其实有些头文件中就
有不少系统已经造好的函数,它们叫做标准库(StandardLibrary)函数。我们包含(include)一个头文件,就像是到某个工具库里面去找一个工具一样。所以,要使用系统定义好的一些函数,我们必须知道这些函数在哪个头文件里
,就好像使用工具我们必须知道这个工具放在哪个工具库里面。C++语言的核心部分很小,其外壳却十分丰富。这个外壳中提供丰富的库函数。程序员使用库函数无须再自行定义,只要注意以下三点便可:(1)了解函数的功能(2)了解函数的原型(3)库函数按
功能分为不同的库,每个库都有相应的头文件,给出了该库中各个函数的原型声明等有关信息。程序员使用库函数之前只需在程序中使用#include指令嵌入相应的头文件而不必再进行函数的原型说明。4.1.3函数的声明和定义1.函数的声明在C++中,函数原型就是函数的声
明。所以,函数原型除了向用户说明如何使用一个函数以外,还告诉电脑存在这样一个可以使用的函数。我们已经介绍了函数原型的结构,只不过“产生结果类型”这个名称是为了方便理解而起的。它应该称为“返回值类型”,用任意一种
数据类型来表示,比如int或者char等等,当然还包括空类型void。多个参数则构成了“参数表”,表示运行这个函数需要哪些数据。于是,函数原型的结构就是:返回值类型函数名(参数表);函数声明同变量的声明一样,是一句语句。所以在语
句结束要加上分号“;”。函数名、参数名的规则和注意事项同变量名一样。4.1.3函数的声明和定义2.函数的定义说完了函数的声明,我们来说函数的定义。其实函数的定义对大家来说是比较熟悉的。因为我们之前所写的程序都是对主函数的定义。4.1.4主函数main()主函数是一个特殊的函数,不管
把它放在代码的什么位置,每个程序的运行都是从主函数开始的。所以,我们说每个程序有且只能有一个主函数,否则电脑将不知道从何运行。既然电脑知道必须有且只能有一个主函数,那么就没必要去写主函数的函数原型了。主函数也能返回值。根据最新的ANSIC++标准,主函数应该返回一个整型数值,返回这个
值的目的是为了将程序的运行结果告知系统,比如程序是否正常结束,是否异常终止等等。一般地,如果返回0表示程序正常结束,返回其他值则表示程序异常终止。4.1.5函数调用格式及调用方式有两种不同方式的函数调用:作为表达式的函数调用和作为语句的函数调用。4.2函数存在的意义、为什
么要使用函数一、现在要设计一个“学生信息处理程序”,需要完成四项工作,分别是记录学生的基本情况、学生成绩统计、优秀学生情况统计和信息输出。如果我们把四项工作全都写在主函数里面,那么我们就很难分清那一段代码在做什么。多层次的缩进和不能重复的变量名给我们阅读程序带来了困难。如果我们为每一个功能编写
一个函数,那么根据函数名,每个函数的功能就很清晰了。如果我们要修改某一个函数的功能,其他的函数也丝毫不会受到影响。所以,函数的存在增强了程序的可读性。二、需要设计一个规模很大的程序,它有几千项功能,把这些功能都编写在一个主函数里就只能由一个人来编写,因为每个人解决问题的思路是不同的,而且
在主函数中的变量名是不能重复的,只有编写者自己知道哪些变量名是可以使用的。这样一来,没有一年半载,这个程序是无法完成的。4.2函数存在的意义、为什么要使用函数如果我们把这几千项功能分拆为一些函数,分给
几百个人去编写,那么用不了几天时间这些函数就都能够完成了。最后用主函数把这些完成的函数组织一下,一个程序很快就完工了。所以,函数能够提高团队开发的效率。它就像把各个常用而不相关联的功能做成一块块“积木”。完成了函数的编写,编程就像搭积木一
样方便了。三、程序会占用一定的内存用来存放数据。如果没有函数,那么在程序的任何一个地方都能够访问或修改这些数据。这种数据的非正常改变对程序的运行是有害的,给调试程序也会带来很多麻烦。如果我们把若干项功能分拆为函数,则只要把函数原型提供
出来就可以了,不需要将数据提供出来。一般情况下,别的函数无法修改本函数内的数据,而函数的实现方法对外也是保密的。我们把这种特性称为函数的黑盒特性。4.3函数重载在C++中,我们也能够把具有相同功能的函数整合到一个函数上,而不必去写好多个函数名不
同的函数,这叫做函数的重载(Overload)。重载的本质是多个函数共用同一个函数名。4.4函数的默认参数我们在调用函数时,可能会要填写很多的参数,那么电脑能否像自动洗衣机一样,让我们偷个懒,帮我们把参数都自动填好呢?我们知道,所谓自动洗衣功能就是
使用其预置好的程序进行洗涤。如果我们也将函数的参数预置好,那么我们同样可以不必填写参数就能让函数运作起来。这些预置的参数称为默认参数。4.4.1定义默认参数的顺序当一个函数具有多个参数时,定义默认参数的方向是从右向左的,即以最后一个参
数定位的;而匹配参数的方向是从左向右的,即以第一个参数定位的,如图4-3所示:4.4.2默认参数和重载函数的混淆当我们调用函数fn(1)的时候,三个函数都是可以匹配的,因为电脑可以认为我们省略了后面的参数;当我们调用函数fn(1,1)的时候,后两个函数也都是可以匹配的……由于电
脑无法确认我们到底想要调用哪个函数,所以导致了错误的发生。因此,我们在同时使用重载函数和默认参数的时候,要注意到这一点。4.5C++中函数变量的引用给别人起绰号是件不好的事情,但是在程序设计中,给变量或参数起个绰号却会给我们带来一些方便。绰号,就是另一种称呼。绰号和本名都是指同一样东西,绰
号也是个名称,所以它的命名规则其他的命名规则一样。另外,“绰号”显然也不能和“本名”相同。这种给变量起“绰号”的操作称为引用(Reference),“绰号”称为引用名4.5C++中函数变量的引用4.5.1引用4.5.2用引用传递参数4.6C++函数的递归调用
在高中数学中,我们学习过数列。我们知道数列有两种表示方法,一种称为通项公式,即项an和项数n的关系;还有一种称为递推公式,即后一项an和前一项a(n-1)之间的关系。通项公式能够一下子把an求解出来,而递推公式则要根据首项的值多次推导才能把第n项的值慢
慢推导出来。如果有一个较为复杂的数列的递推公式,人工将其转化为通项公式或者将其的每一项求出实在非常麻烦,那么我们能不能直接把这个递推公式交给计算机,让它来为我们求解呢?我们说过,在任何一个函数体内不
能出现其它函数的定义。但是,在任一个函数体内可以调用任何函数,包括该函数本身。直接或者间接地在函数体内调用函数本身的现象称为函数的递归调用。4.7内嵌函数程序在执行过程中,每调用一次函数,就要在调用与返回过程中付出一定的时间和空间代价用于处理现场,通常是用堆栈进行保护,
返回时退栈恢复现场。但当函数较小,又反复使用时,处理现场的开销会急剧增大。若把函数嵌入函数调用处,便可以大大提高运行速度。这当然是以牺牲存储空间作为代价的内嵌函数有如下限制:(1)内嵌函数中不能有循环结构或switch结构及goto语句;(2)内嵌函数中不能含有任何静
态数据及数据声明。由于有以上限制,使用起来不是太方便。因此,除非必要,一般尽量不使用内嵌函数。4.8函数和变量的作用域在C++中,程序是由各种函数按一定顺序组成的,无论是函数本身,还是函数中的变量,都有其存储属性,存储属性是对作用域和生存期的抽象。4.8.1C++的存储属性在C++中,程序
是由各种函数按一定顺序组成的,无论是函数本身,还是函数中的变量,都有其存储属性,存储属性是对作用域和生存期的抽象。4.8.1C++的存储属性C++的存储属性有以下四种:auto(自动)register(
寄存器)extern(外部)static(静态)1.auto型属于auto型的程序实体,称为自动程序实体,它采用的是栈分配存储模式。在C++中,auto可以不写,即程序实体的默认方式为auto2
.register型register型程序实体和auto型程序实体的作用相同,只不过其采用的是寄存器存储模式,执行速度较快。当寄存器全部被占用后,余下的register型程序实体自动成为auto型的。只有整型程序变量可以成为真正的register型变量。
3.extern型用extern声明的程序实体称为外部程序实体。它是为配合全局变量的使用而定义的。所谓外部变量,就是在块外保持不变,并不因块内发生变化而影响到块外。4.8.1C++的存储属性C++的存储属性有以下四种:auto(自动)reg
ister(寄存器)extern(外部)static(静态)1.auto型属于auto型的程序实体,称为自动程序实体,它采用的是栈分配存储模式。在C++中,auto可以不写,即程序实体的默认方式为auto2.register型reg
ister型程序实体和auto型程序实体的作用相同,只不过其采用的是寄存器存储模式,执行速度较快。当寄存器全部被占用后,余下的register型程序实体自动成为auto型的。只有整型程序变量可以成为真正的register型
变量。3.extern型用extern声明的程序实体称为外部程序实体。它是为配合全局变量的使用而定义的。所谓外部变量,就是在块外保持不变,并不因块内发生变化而影响到块外。4.8.2函数的作用域一般说来,
函数的作用域是全局的,不但在定义它的文件中可以调用,而且在同一应用系统的其它程序文件中也可以调用。如果一函数仅仅是为了提供给同一文件中的函数调用,则应该将其说明为static,以防止可能存在的名字冲突。这样的作用域称为文件作用域。例如,若将函数add定义为staticl
ongadd(longa,longb){returna+b;}则add只允许被同一程序文件中的函数调用。在多人分工合作的情况下,这种对函数作用域的限制很有用:同一系统中的由不同人员设计的文件中即使存在着同名函数,也互不干扰,因此设计人员可以放心地为函数取自己喜欢的名字。4.8.3变量
的作用域和生存期函数中总是要使用变量的,因此与函数有密切关系的一个问题就是变量的作用域及其生存期。依据变量作用域的不同,变量可分为全局变量和局部变量。函数体内声明的变量仅在该函数体内有效,别的函数是无法使用的。并且在函数运行结束后,这些变量也将消失了。我
们把这些在函数体内声明的变量称为局部变量(LocalVariable)。然而,可能会遇到这样的问题:我们想要创建一个变量作为数据缓冲区(Buffer),分别供数据生成、数据处理和数据输出三个函数使用,三个函数都要能够读取或修改这个变量的值
。显然通过传递参数或返回值来解决这个问题是非常麻烦的。那么,我们能否建立一个变量能够让这三个函数共同使用呢?在C++中,我们可以在函数体外声明一个变量,它称为全局变量(globalvariable)。所谓全局,是指对于所有函数都能够使用。4.8.4C++变量的可
见性我们已经说明,变量可以使用的范围是由变量的作用域决定。不同层次的变量的作用域,就好像大小不一的纸片。把它们堆叠起来,就会发生部分纸片被遮盖的情况。我们把这种变量作用域的遮盖情况称为变量的可见性(Visibility)。如下面的图4-4所示
:4.9编译预处理1.宏定义宏定义也称宏代换,实际就是用一个宏名字来命名一个字符串,2.文件包含文件包含的作用是让编译器把一个已经进入系统的源文件嵌入到当前源文件中该指令处。3.条件编译条件编译是源文件内系统级的选择结构*4.10函数模板C++提供了函数模板(functiontemp
late)。所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实
参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能通用函数定义在建立函数模板时,只要将程序中定义的第一个函数首部的类型改为T即可。即用虚拟的类型名T代替具体的数据类型。在对程序进行编译时,遇到第13行调用函数max(i1,i2,i3),编译系统会将函数名max与模板max相匹配,将实参的
类型取代了函数模板中的虚拟类型T。此时相当于已定义了一个函数:intmax(inta,intb,intc){if(b>a)a=b;if(c>a)a=c;returna;}然后调用它。后面两行(14,15行)的情况类似。
类型参数可以不只一个,可以根据需要确定个数。如template<classT1,typenameT2>可以看到,用函数模板比函数重载更方便,程序更简洁。但应注意它只适用于函数的参数个数相同而类型不同,且函数体相同的情况,如果参数的个数不同,则不能用函数模板。