📄 03章 函数.txt
字号:
30
31 if { z > max )
32 max = z;
33
34 return max;
35 }
输出结果:
Enter three integers: 22 85 17
Maximum is: 85
Enter three integers: 92 35 14
Maximum is: 92
Enter three integers: 45 19 98
Maximum is: 98
图3.4 自定义函数maximum
3.6 函数原型
C++的最重要特性之一是函数原型(function prototype)函数原型告诉编译器函数名称、函数返回的数据类型、函数要接收的参数个数、参数类型和参数顺序,编译器用函数原型验证函数调用。
旧版C语言不进行这种检查,因此函数调用出错时,编译器可能无法发现错误。这种调用可能造成致命执行时错误或非致命执行时错误,导致很难确认的逻辑错误,函数原型能纠正这个缺陷。
软件工程视点3.8
C++中要求函数原型。用#include预处理指令从相应库的头文件中取得标准库函数的函数原型。也可以用#include取得包含读者和小组成员使用的函数原型的头文件。
软件工程视点3.9
如果函数定义出现在程序中首次使用函数之前,则不需要函数原型,这时函数定义就作为函数原型。
图3.4中maximum函数原型为:
int maximum(int,int,int);
这个原型表示maximum取三个int类型参数,返回int类型结果。注意这个函数原型与maximum函
数定义的首部相同,只是不包括参数名(x、y、z)。
编程技巧3.6
许多程序置用函数原型中的参数名来说明函数,编译器将忽略这些名称。
常见编程错误3.11
忘记函数原型末尾的分号是个语法错误。
函数原型中包括函数名和参数类型的部分称为函数签名(function signature)或签名(signature)。函数签名不包括函数返回类型。
常见编程错误3.12
函数调用不符合函数原型是个语法错误。
常见编程错误3.13
函数定义不符合函数原型是个语法错误。
作为上述“常见编程错误”的例子.图3.4中如果函数原型写成:
void maximum( int,int,int );
则编译器报告错误,因为函数原型中的void返回类型与函数首部中的int返回类型不同。
函数原型的另一个重要特性是强制参数类型转换(coercion of argument),即强制参数为相应类型。例如,数学库函数sqrt可以用整数参数调用,虽然math.h中的函数原型指定double参数,但函数仍然可以顺利工作。下列语句:
cout<<sqrt(4));
能正确地求值sqrt(4),并打印结果2。函数原型使编译器将整数参数值4变为double值4.0,然后再传人sqrt中。一般来说.与函数原型中参数类型不完全相符的参数值转换为正确类型之后再进行函数调用。这种转换可能在不遵照C++提升规则(promotion rule)时造成不正确的结果。提升规则指定一种类型转换为另一种类型时怎样才能不丢失数据。在上述sqrt的例子中,int自动转换为double而不改变数值,但如果将double转换为int,则会截去double的小数部分。将大整数的类型变为小整数的类型(例如long变为short)可能造成数值改变。
提升规则适用于包含两种或多种数据类型的表达式,这种表达式也称为混合类型表达式(mixed-type expressionL混合类型表达式中每个值的类型提升为表达式中最高的类型(实际上是生成每个值的临时值并在表达式中使用,原值保持不变)。提升的另一个常见用法是在函数参数类型不符合函数定义中指定的参数类型时。图3.5显示了内部数据类型由高到低的顺序。
数据类型
long double
double
float
unsigned long int (同unsigned long)
long int (同long)
unsigned int (同unsigned)
int
unsigned short int (同unsigned short)
short int (同short)
unsigned char
short
char
图 3.5 内部数据类型由高到低的顺序
将数值转换为较低类型可能导致数值不正确。因此,要将数值转换为较低类型,只能显式将该值赋给较低类型的变量或使用强制类型转换运算符。函数参数值变为函数原型中的参数类型.就像直接赋给这些类型的变量一样。如果square函数使用整型参数(图3.3)而用浮点参数调用,则该参数换算为int(将数值转换为较低类型),square通常返回不正确的值。例如,square(4.5)返回16而不是20.25。
常见编程错误7.14
将提升规则中较高的数据类型变为较低的数据类型可能改变数据值。
常见编程错误1.15
函数未定义先调用时如果不定义函数原型属于语法错误。
软件工程视点3.10
在文件中,放在任何函数定义之外的函数原型可用于该函数原型之后所有对该函数的调用。放在函数之中的函数原型只适用于该函数中的调用。
3.7 头文件
每个标准库都有对应的头文件(header file),包含库中所有函数的函数原型和这些函数所需各种数据类型和常量的定义。图3.6列出了C++程序中可能包括的常用C++标准库头文件。图3.6中多次出现的宏(macro)将在第17章“预处理器”中详细介绍。以.h结尾的头文件是旧式头文件。
对每个旧式头文件,我们介绍新标准中使用的版本。
程序员可以生成自定义头文件,自定义头文件应以.h结尾.可以用#include预处理指令包括自定义头文件。例如,square.h头文件可以用下列指令:
#include "square.h"
放在程序开头。17.2节介绍了包含头文件的其他信息。
旧式头文件 说明
旧式头文件(本书前面使用)
(assert.h> 包含增加诊断以程序调试的宏和信息。这个头文件的新版本为<cassert>
<ctype.h> 包含测试某些字符属性的函数原型和将小写字母变为大写字母,将大写字母变为小
写字母的函数原型。这个头文件的新版本为<cctype>
<float.h> 包含系统的浮点长度限制。这个头文件的新版本为<cfloat>
<limits.h> 包含系统的整数长度限制。这个头文件的新版本为<climits>
<math.h> 包含数学库函数的函数原型。这个头文件的新版本为<cmath>
<stdio.h> 包含标准输入/输出库函数的函数原型及其使用信息。这个头文件的新版本为<cstdio>
<stdlib.h> 包含将数字变为文本、将文本变为数字、内存分配、随机数和各种其它工具函数的函
数原型。这个头文件新版本为<cstdlib>
<string.h> 包含C语言格式的字符串处理函数的函数原型。这个头文件的新版本为<cstring>
<time.h> 包含操作时间和是期的函数原型和类型。这个头文件的新版本为<ctime>
<iostream.h> 包含标准输入/输出函数的函数原型。这个头文件的新版本为<iostream>
<iomanip.h> 包含能够格式化数据流的流操纵算子的函数原型。这个头文件的新版本为<iomanip>
<fstream.h> 包含从磁盘文件输入输出到磁盘文件的函数原型。这个头文件的新版本为<fstream>
标准库头文件 说明
<utility> 包含许多标准库头文件使用的类和函数
<vector>、<list>、 包含实现标准库容器的类的头文件。容器在程序执行期间用于存放数据。我们将在
<deque>、<queue>、 “标准模板库”一章介绍这些头文件
<stack>、<map>、
<set>、<bitset>
<functional> 包含用于标准库算法的类和函数
<memory> 包含用于向标准库容器分配内存的标准库使用的类和函数
<iterator> 包含标准库容器中操作数据的类
<algorithm> 包含标准库容器中操作数据的函数
<exception> 这些头文件包含用于异常处理的类(见第13章)
<stdexcept>
<string> 包含标准库中string类的定义(见第19章)
<sstream> 包含从内存字符串输入和输出到内存字符串的函数原型
<locale> 包含通常在流处理中用于处理其它语言形式数据的类和函数(例如货币格式、
排序字符串、字符表示等)
<limits> 包含定义每种计算机平台特定数字数据类型的类
<typeinfo> 包含运行时类型信息的类(在执行时确定数据类型)
图 3.6 常用C++标准库头文件
3.8 随机数产生器
下面要介绍一个在模拟事件和游戏的程序中常用的组件。本节和下节开发一个结构良好、包括多个函数的游戏程序。程序中要使用前面介绍的大多数控制结构。
在赌场上,人人都关心的一个问题就是机会元素(element of chance),也就是赢钱的运气。这个机会元素可以用标准库中的rand函数引入计算机应用程序中。
考虑下列语句:
i=rand();
rand函数产生O到RAND_MAX之间的整数(这是<stdlib.h>头文件中定义的符号常量)。RAND_MAX的值至少应为32767,也就是两个字节(即16位)所能表示的最大整数值。如果rand函数真的可以随机产生整数,则每次调用rand函数时,o到RAND_MAX之间的每个数出现的机会(chance)或概率(probability)是相等的。
rand函数产生的数值范围可能与特定应用中所要求的数值范围不同。例如,模拟掷硬币的程序只要0(正面)和1(反面),模拟投骰子的程序只要1到6之间的随机整数,视频游戏中预测飞船(有四种类型)下一个类型的程序只要1到4之间的随机整数。
要演示rand函数,我们开发一个程序,模拟投骰子20次并打印每次的值。rand函数的函数原型见<stdlib.h>。我们使用求模运算符(%)和rand函数,如下所示:
rand( ) % 6
产生0到5的整数,称为比例缩放(scaling)。数字6称为比例因子(scalingfactor)。然后我们将产生的数值范围加1。得到所要结果。图3.7确认了产生的结果在1到6之间。
要显示这些数值的出现机会近似均等.图3.8模拟投骰子6000次。1到6的每个数值大约都出
现1000次。
从程序输出可见,通过比例缩放和移动,可以利用rand函数真实地模拟投骰子。注意程序用不到switch结构中提供的default case,但我们还是加上default case,这是个良好的编程习惯。第4章数组将介绍如何把整个switch结构转换成简单的单行语句。
1 // Fig. 3.7: figO307.cpp
2 // Shifted, scaled integers produced by 1 + rand( ) % 6
3 #include <iostream.h>
4 #include <iomanip.h>
5 #include <stdlib.h>
6
7 int main( }
8
9 for( int i = 1; i <= 20; i ++){
10 cout<< setw(10 ) << { 1 +rand( ) % 6 );
11
12 if( i % 5 == 0 )
13 cout << endl;
14 }
15
16 return O;
17 }
输出结果:
5 5 3 5 5
2 4 2 5 5
5 3 2 2 1
5 1 4 6 4
图3.7 比例缩放和移动“rand()%6”产生的整数
1 // Fig. 3.8:fig03 08.cpp
2 // Roll a six-sided die 6000 times
3 #include <iostream.h>
4 #include <iomanip.h>
5 #include <stdlib.h>
6
7 int main( )
8{
9 int frequencyl = 0, frequency2 = 0,
10 frequency3 = 0, frequency4 = 0,
11 frequency5 = 0, frequency6 = 0,
12 face;
13
14 forf( int roll = 1; roll <= 6000; roll++ ) {
15 ace = 1 + rand( ) % 6;
16
17 switch ( face ) {
18 case 1:
19 ++frequencyl;
20 break;
21 case 2:
22 ++frequency2;
23 break;
24 case 3:
25 ++frequency3;
26 break;
27 case 4:
28 ++frequency4;
29 break;
30 case 5:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -