教学目标 了解如何由函数模块化地构造程序 能够生成新函数 了解函数之间传递信息的机制 介绍使用随机数产生器的模拟技术 了解标识符如何限于特定程序区域 如何编写和使用调用自己的函数3.1简介解决实际问题的大多数程序都比前儿章介绍的程序要大得多。经验表明,要开发和维护大程序,最好的办法是从更容易管理的小块和小组件开始。这种方法称 为“分而治之,各个击破(d i vi d e a n d c o n q ue r)o本章介绍C+语言中的许多关键特性,可以帮助设计、实现、操作和维护大程序。3.2 C+程序组件C+中的模块称为函数(f un c ti o n)和类(c l a ss)。C+程序一般是将程序员编写的新函数与C+标准库(sta n d a r d 1 i b r a r y)中提供的预装函数组合而成的,通常是将程序员编写的新类与各种类库中提供的预装类组合而成的。本章主要介绍函数,第6章开始将详细介绍类。C+标准库提供了丰富的函数集合,可以进行常用数学计算、字符串操作、字符操作、输人/输出、错误检查和许多其他有用的操作。这就使程序员的工作更加轻松,因为这些函数提供了程序员需要的许多功能。C+标准库函数是在C+编程环境中提供的。编程技巧3.1要熟悉C+标准库提供的类和函数集合。软件工程视点3.1不要事事从头做起。要尽可能利用C+标准库提供的函数而不是生成新函数,从而减少程序开发时间。可移植性提示3.1利用C+标准库提供的函教能使程序可移植性更强。性能提示3.1不要改写现有库程序以使其更有效,这些过程的性能通常已经是最优的。程序员可以通过编写函数定义程序中多处使用的特定任务,这些通常称为程序员定义的函数(p r o g r a r m m e r-d e f i n e d f un c ti o n)定义函数的语句通常只写一次,这些语句是其他函数无法访问的。通过函数调用(f un c ti o n c a l l)来调用(i n vo ke,即让其完成指定任务)函数。函数调用指定函数名和提供被调用函数完成工作所需的信息 作为参数L可以把这种形式与管理的层次形式相比,老板(调用函数或调用者)要求工人(被调用函数)完成任务并在任务完成之后返回(即报告)结果。老板函数并不知道工人函数如何完成工作。工人又可能调用其他工人函数,这是老板所不知道的。稍后会介绍这种隐蔽实现细节如何促进良好的软件工程。田3.1显示了 main函数以层次方式和儿个工人函数通信。注意w o r ke r 1是w o r ke r 4和w o r ke r 5的老板函数。函数之间的关系也可能与图中所示的层次结构有所不同。3.3数学函数库数学函数库使程序员可以进行某些常见数学计算。我们这里用各种数学库函数介绍函数概念。本书稍后会介绍C+标准库中的许多其他函数。调用函数时,通常写上函数名,然后是一对括号,括号中写上函数参数(或逗号分隔的参数表)。例如程序员可以用下列语句计算和打印9 0 0.0的平方根:c o u t 0,ab s(x)=xx=0,ab s (x)=0.0 x 0,ab s(x)=-xf lo o r (x)将X取整为不大于X的最大整数f lo o r (9.2)=9.0f lo o r (-9.8)=10.0f mo d(x,y)x/y的浮点数余数f mo d(1 3.6 5 7,2.3 3 3)=1.9 9 2lo g(x)x的自然对数(底数为e)lo g(2.7 1 8 2 8 2)=1.0lo g (7.3 8 9 0 5 6)=2.0lo g lO(x)x的对数(底数为1 0)l o g d o.o)=i.ol o g(1 0 0.0)=2.0p o w(x,y)x的y次方(x y)p o w(2,7)=1 2 8p o w(9,.5)=3s i n(x)x(弧度)的正弦s i n(0.0)=0s q r t(x)X的平方根s q r t(9 0 0.0)=3 0.0s q r t 0)=3.0ta n (x)x(弧度的正切ta n (0.0)=03.4函数函数使程序员可以将程序模块化。函数定义中声明的所有变量都是局部变量(l o c a l v a r i a b l e),只在所在的函数中有效。大多数函数有一系列参数,提供函数之间沟通信息的方式。函数参数也是局部变量。软件工程视点3.2在包含多个函数的程序中,m a i n应实现为一组函数调用,这些函数进行大量的程序工作。将程序函数化的目的有儿个,“分而治之、各个击破”的方法使程序开发更容易管理。另一个目的是软件复用性(s o ftw a r e r e u s a b i l i ty),用现有函数作为基本组件,生成新程序。软件复用性是面向对象编程的主要因素。有了好的函数命名和定义,程序就可以由完成特定任务的标准化函数生成,而不必用自定义的代码生成。第三个目的是避免程序中的重复代码,将代码打包成函数使该代码可以从程序中的多个位置执行,只要调用函数即可。软件工程视点3.1每个函数只限于完成一个定义良好的任务,函数名应有效地表达这个任务,这样可以提高软件复用性。软件工程视点3.4如果无法用简单名称表达函数的作用,则可能是定义的函数要完成的任务太分散。通常应把这种函数分解为几个更小的函数。3.5函数定义前面介绍的每个程序都有一个m a i n函数,调用标准库函数完成工作。现在要考虑程序员如何编写自定义函数。考虑一个程序,用自定义函数,s q u a r e计算整数1到1 0的平方(如图3.3)。1 /Fi g.3.3:fi g 0 3 _ 0 3.c p p2 /C r e a ti n g a n d u s i n g a p r o g r a e r-d e fi n e d fu n c ti o n3 S i n c l u d e 45 i n t s q u a r e(i n t);/fu n c ti o n p r o to ty p e(函数原型)67 i n t m a i n()(S9 fo r (i n x =1;x =1 0;x+)1 0 c o u t s q u a r e(x );1 11 2 c o u t e n d l;1 3 r e tu r n 0;1 4 )1 51 6 /Fu n c ti o n d e fi n i ti o n(函数定义)1 7 i n t s q u a r e(i n t y )1 8 (1 9 r e tu r n y *y;2 0 )输出结果:1 4 9 1 6 2 5 3 6 4 9 6 4 8 1 1 0 0图 3.3生成和使用自定义函数编程技巧3.2在函数定义之间加上空行,分隔函数和提高程序可读性。m a i n 中调用函数s q u a r e 如下所示:s q u a r e(x)函数s q u a r e 在参数y中接收x 值的副本。然后s q u a r e 计算y*y,所得结果返回m a i n 中调用s q u a r e 的位置,并显示结果,注意函数调用不改变x的值。这个过程用f o r 重复结构重复十次。s q u a r e 定义表示s q u a r e 需要整数参数y。函数名前面的关键字i n t 表示s q u a r e 返回一个整数结果。s q u a r e 中的r e t u r n 语句将计算结果返回调用函数。第 5 行:i n t s q u a r e(i n t);是个函数原型(f u n c t i o n p r o t o t y p e)。括号中的数据类型i n t 告诉编译器,函数 s q u a r e 要求调用者提供整数值。函数名s q u a r e 左边的数据类型i n t 告诉编译器,函数s q u a r e 向调用者返回整数值。编译器通过函数原型检查s q u a r e 调用是否包含正确的返回类型、参数个数、参数类型和参数顺序。如果函数定义出现在程序中首次使用该函数之前,则不需要函数原型,这种情况下,函数定义也作为函数原型。如果图3 3 中第17 行到第2 0行在m a i n 之前,则第5 行的函数原型是不需要的。函数原型将在第3.6 节详细介绍。函数定义格式如下:r e t u r n-v a l u e-t y p e f u n c t i o n-n a m e(p a r a m e t e r-l i s t)d e c l a r a t i o n s a n d s t a t e m e n t s)函数名(f u n c t i o n-n a m e)是任何有效标识符,返回值类型(r e t u r n-v a l u e-t y p e)是函数向调用者返回值的数据类型,返回值类型v o i d 表示函数没有返回值。不指定返回值类型时默认为i n t o常见编程错误3.2如果函数原型指定返回类型不是i n t,则函数定义中省略返回值类型是个语法错误。常见编程错误3.3需要返回值的函数中不返回值是个语法错误。常见编程错误3.4返回类型声明为v o i d 的函数中返回值是个语法错误。编程技巧3.3尽管省略返回类型时默认为i n t,但最好显式指定返回类型。参数表是逗号分隔的清单,包含函数被调用时接受的参数声明。如果函数不接受任何值,则参数表为v o i d 或空白。函数参数表中的每个参数应显式指定类型。常见编程错误1.5同类函数参数应声明为f l o a t x,f l o a t y 而不是f l o a t x,y,参数声明f l o a tx、y 实际上会报告编译错误,因为参数表中的每个参数应显式指定类型。常见编程错误3.6将分号放在函数定义中参数表的右括号之后是个语法槽误。常见编程错误3.7函数中再次把函数参数定义为局部变量是个语法错误。编程技巧3.4向函数传递参数和函数定义中的对应参数可以同名,但最好不要同名,以免引起歧义。常见编程错误1.8函数调用中的()实际上是C+中的运算符,使函数可以被调用。如果函数不取参数,则省略函数调用中的。并不是语法错误,但函数可能会在需要的时候不能调用。花括号中的声明(d e c l a r a t i o n)和语句(s t a t e m e n t)构成函数体(f u c t i o nb o d y),函数体也称为块(b l o c k),块是包括声明的复合语句。变量可以在任何块中声明,而且块也可以嵌套。任何情况下不能在一个函数中定义另一个函数。常见编程错误3.9在一个函数中定义另一个函数是个语法错误。编程技巧3.5选择有意义的函数名和有意义的参数名能使程序更易读,避免大量使用注释语句。软件工程视点3.5函数应能放在一个编辑器窗口中。不管函数有多长,应该都能很好地完成个任务。小函数能提高函数的复用性。软件工程视点3.6程序应写成一组小函数的集合.使得程序更容易编写、调试、维护和修改。软件工程视点3.7需要大量参数的函数可能要完成大量的任务。应把函数分成更小的函数来完成各个任务,函数的首部最好能在一行中放下。常见编程错误3.1 0如果函数原型、函数首部与函数调用的形参和实参的个数、类型、顺序以及返回值类型不相符,则是个语法错误。将控制返回函数调用点的方法有三种。如果函数不返回结果,则控制在到达函数结束的右花括号时或执行下列语句时返回:r e t u r n;如果函数返回结果,则下列语句:return expression;向调用者返叵I 表达式的值。第二个例子用自定义函数maximum确定和返回三个整数中的最大值(如图3.4)。输入三个整数,然后将整数传递到maximum中,确定最大值。这个值用maximum中的return语句返回main。返回的值赋给变量largest,然后打印。1/Fig.3.4:fig0 30 4.cpp2/Finding the maximum of three integers3 ttinclude 45 int maxi mu