📄 03章 函数.txt
字号:
C++大学教程(第3章 函数-01)
教学目标
●了解如何由函数模块化地构造程序
●能够生成新函数
●了解函数之间传递信息的机制
●介绍使用随机数产生器的模拟技术
●了解标识符如何限于特定程序区域
●如何编写和使用调用自己的函数
3.1 简介
解决实际问题的大多数程序都比前几章介绍的程序要大得多。经验表明,要开发和维护大程序,最好的办法是从更容易管理的小块和小组件开始。这种方法称为“分而治之,各个击破”(divideand conquer)。本章介绍C++语言中的许多关键特性,可以帮助设计、实现、操作和维护大程序。
3.2 C++程序组件
C++中的模块称为函数(function)和类(class)。C++程序一般是将程序员编写的新函数与C++标准库(standard library)中提供的预装函数组合而成的,通常是将程序员编写的新类与各种类库中提供的预装类组合而成的。本章主要介绍函数,第6章开始将详细介绍类。
C++标准库提供了丰富的函数集合,可以进行常用数学计算、字符串操作、字符操作、输人/输出、错误检查和许多其他有用的操作。这就使程序员的工作更加轻松,因为这些函数提供了程序员需要的许多功能。C++标准库函数是在C++编程环境中提供的。
编程技巧3.1
要熟悉C++标准库提供的类和函数集合。
软件工程视点3.1
不要事事从头做起。要尽可能利用C++标准库提供的函数而不是生成新函数,从而减少程序开发时间。
可移植性提示3.1
利用C++标准库提供的函教能使程序可移植性更强。
性能提示3.1
不要改写现有库程序以使其更有效,这些过程的性能通常已经是最优的。
程序员可以通过编写函数定义程序中多处使用的特定任务,这些通常称为程序员定义的函数(prograrmmer-defined function)。定义函数的语句通常只写一次,这些语句是其他函数无法访问的。
通过函数调用(function call)来调用(invoke,即让其完成指定任务)函数。函数调用指定函数名和提供被调用函数完成工作所需的信息<作为参数L可以把这种形式与管理的层次形式相比,老板(调用函数或调用者)要求工人(被调用函数)完成任务并在任务完成之后返回(即报告)结果。老板函数并不知道工人函数如何完成工作。工人又可能调用其他工人函数,这是老板所不知道的。稍后会介绍这种隐蔽实现细节如何促进良好的软件工程。田3.1显示了main函数以层次方式和几个工人函数通信。注意workerl是worker4和worker5的老板函数。函数之间的关系也可能与图中所示的层次结构有所不同。
----------------------
3.3 数学函数库
数学函数库使程序员可以进行某些常见数学计算。我们这里用各种数学库函数介绍函数概念。本书稍后会介绍c++标准库中的许多其他函数。
调用函数时,通常写上函数名,然后是一对括号,括号中写上函数参数(或逗号分隔的参数表)。例如程序员可以用下列语句计算和打印900.0的平方根:
cout << sqrt(900.O);
执行这个语句时,数学库函数sqrt计算括号中所包含数字(900.0)的平方根。数字900.0是sqrt函数的参数。上述语句打印30。sqrtd函数取double类型参数,返回double类型结果。数学函数库中的所有函数都返回double类型结果。要使用数学库函数,需要在程序中包含math.h头文件(这个头文件在新的C++标准库中称为cmath)。
常见编程错误3.1
使用数学库孙数而不包括math.h文件是个语法错误。程序中使用的每个标准库函数都应包括标准头文件。
函数参数可取常量、变量或表达式。如果c1=13.0、d=3.0和f=4.0,则下列语句:
cout << sqrt (cl + d * f);
计算并打印13.0+3.0*4.0=25.0的平方根,即5(因为C++通常对没有小数部分的浮点数不打印小数点和后面的零)。
图3.2总结了一些数学库函数。图中变量x和y为double类型。
------------------------------------------------------------------------------
函数 说明 举例
------------------------------------------------------------------------------
ceil(x) 将x取整为不小于x的最小整数 ceil(9.2)=10.0
ceil(-9.8)=-9.0
cos(x) x(弧度)的余弦 cos(0.0)=1.0
exp(x) 指数函数ex exp(1.0)=2.71828
exp(2.0)=7.38906
fabs(x) x的绝对值 x>0,abs(x)=x
x=0,abs(x)=0.0
x<0,abs(x)=-x
floor(x) 将x取整为不大于x的最大整数 floor(9.2)=9.0
floor(-9.8)=-10.0
fmod(x,y) x/y的浮点数余数 fmod(13.657,2.333)=1.992
log(x) x的自然对数(底数为e) log(2.718282)=1.0
log(7.389056)=2.0
log10(x) x的对数(底数为10) log(10.0)=1.0
log(100.0)=2.0
pow(x,y) x的y次方(xy) pow(2,7)=128
pow(9,.5)=3
sin(x) x(弧度)的正弦 sin(0.0)=0
sqrt(x) x的平方根 sqrt(900.0)=30.0
sqrt(9.0)=3.0
tan(x) x(弧度的正切 tan(0.0)=0
-------------------------------------------------------------------------------
3.4 函数
函数使程序员可以将程序模块化。函数定义中声明的所有变量都是局部变量(local variable),只在所在的函数中有效。大多数函数有一系列参数,提供函数之间沟通信息的方式。函数参数也是局部变量。
软件工程视点3.2
在包含多个函数的程序中,main应实现为一组函数调用,这些函数进行大量的程序工作。
将程序函数化的目的有几个,“分而治之、各个击破”的方法使程序开发更容易管理。另一个目的是软件复用性(software reusability),用现有函数作为基本组件,生成新程序。软件复用性是面向对象编程的主要因素。有了好的函数命名和定义,程序就可以由完成特定任务的标准化函数生成,而不必用自定义的代码生成。第三个目的是避免程序中的重复代码,将代码打包成函数使该代码可以从程序中的多个位置执行,只要调用函数即可。
软件工程视点3.1
每个函数只限于完成一个定义良好的任务,函数名应有效地表达这个任务,这样可以提高软件复用性。
软件工程视点3.4
如果无法用简单名称表达函数的作用,则可能是定义的函数要完成的任务太分散。通常应把这种函数分
解为几个更小的函数。
3.5 函数定义
前面介绍的每个程序都有一个main函数,调用标准库函数完成工作。现在要考虑程序员如何编写自定义函数。
考虑一个程序,用自定义函数,square计算整数1到10的平方(如图3.3)。
1 // Fig. 3.3: fig03_03.cpp
2 // Creating and using a progra~er-defined function
3 #include <iostream.h>
4
5 int square( int ); // function prototype(函数原型)
6
7 int main( )
(
S
9 for ( in x = 1; x <= 10; x++ )
10 cout<< square( x ) << " " ;
11
12 cout << endl;
13 return 0;
14 }
15
16 // Function definition(函数定义)
17 int square( int y )
18 (
19 return y * y;
2O }
输出结果:
l 4 9 16 25 36 49 64 8l lOO
图 3.3 生成和使用自定义函数
编程技巧3.2
在函数定义之间加上空行,分隔函数和提高程序可读性。
main中调用函数square如下所示:
square(x)
函数square在参数y中接收x值的副本。然后square计算y*y,所得结果返回main中调用square的位置,并显示结果,注意函数调用不改变x的值。这个过程用for重复结构重复十次。
square定义表示square需要整数参数y。函数名前面的关键字int表示square返回一个整数结果。square中的return语句将计算结果返回调用函数。
第5行:
int square(int);
是个函数原型(functionprototype)。括号中的数据类型int告诉编译器,函数square要求调用者提供整数值。函数名square左边的数据类型int告诉编译器,函数square向调用者返回整数值。编译器通过函数原型检查square调用是否包含正确的返回类型、参数个数、参数类型和参数顺序。如果函数定义出现在程序中首次使用该函数之前,则不需要函数原型,这种情况下,函数定义也作为函数原型。如果图33中第17行到第20行在main之前,则第5行的函数原型是不需要的。函数原型将在第3.6节详细介绍。
函数定义格式如下:
return-value-type function-name(parameter-list)
{
declarations and statements
}
函数名(function-name)是任何有效标识符,返回值类型(return-value-type)是函数向调用者返回值的数据类型,返回值类型void表示函数没有返回值。不指定返回值类型时默认为int。
常见编程错误3.2
如果函数原型指定返回类型不是int,则函数定义中省略返回值类型是个语法错误。
常见编程错误3.3
需要返回值的函数中不返回值是个语法错误。
常见编程错误3.4
返回类型声明为void的函数中返回值是个语法错误。
编程技巧3.3
尽管省略返回类型时默认为int,但最好显式指定返回类型。
参数表是逗号分隔的清单,包含函数被调用时接受的参数声明。如果函数不接受任何值,则参数表为void或空白。函数参数表中的每个参数应显式指定类型。
常见编程错误1.5
同类函数参数应声明为float x,float y而不是float x,y,参数声明float x、y实际上会报告编译错误,因为参数表中的每个参数应显式指定类型。
常见编程错误3.6
将分号放在函数定义中参数表的右括号之后是个语法槽误。
常见编程错误3.7
函数中再次把函数参数定义为局部变量是个语法错误。
编程技巧3.4
向函数传递参数和函数定义中的对应参数可以同名,但最好不要同名,以免引起歧义。
常见编程错误1.8
函数调用中的()实际上是C++中的运算符,使函数可以被调用。如果函数不取参数,则省略函数调用中的()并不是语法错误,但函数可能会在需要的时候不能调用。
花括号中的声明(declaration)和语句(statement)构成函数体(fuction body),函数体也称为块(block),块是包括声明的复合语句。变量可以在任何块中声明,而且块也可以嵌套。任何情况下不能在一个函数中定义另一个函数。
常见编程错误3.9
在一个函数中定义另一个函数是个语法错误。
编程技巧3.5
选择有意义的函数名和有意义的参数名能使程序更易读,避免大量使用注释语句。
软件工程视点3.5
函数应能放在一个编辑器窗口中。不管函数有多长,应该都能很好地完成一个任务。小函数能提高函数的复用性。
软件工程视点3.6
程序应写成一组小函数的集合.使得程序更容易编写、调试、维护和修改。
软件工程视点3.7
需要大量参数的函数可能要完成大量的任务。应把函数分成更小的函数来完成各个任务,函数的首部最好能在一行中放下。
常见编程错误3.10
如果函数原型、函数首部与函数调用的形参和实参的个数、类型、顺序以及返回值类型不相符,则是个语法错误。
将控制返回函数调用点的方法有三种。如果函数不返回结果,则控制在到达函数结束的右花括号时或执行下列语句时返回:
return;
如果函数返回结果,则下列语句:
return expression;
向调用者返回表达式的值。
第二个例子用自定义函数maximum确定和返回三个整数中的最大值(如图3.4)。输入三个整数,然后将整数传递到maximum中,确定最大值。这个值用maximum中的return语句返回main。返回的值赋给变量largest,然后打印。
1 // Fig. 3.4: fig0304.cpp
2 // Finding the maximum of three integers
3 #include <iostream.h>
4
5 int maximum( int, int, int ); // function prototype(函数原型)
6
7 int main( )
8 {
9 int a, b, c;
10
11 cout << "Enter three integers: ";
12 cin >> a >> b >> c;
13
14 // a, b and c below are arguments to
15 // the maximum function call(函数调用)
16 cout << "Maximum is: "<< maximum( a, b, c ) << endl;
17
18 return 0;
19 }
2O
21 // function maximum definition
22 // x, y and z below are parameters to
23 // the maximum function definition
24 int maximum( int x, int y, int z )
25 {
26 int max = x;
27
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -