C++学习教程及习题第三章.docx
教学冃标 了解如何由函数模块化地构造程序 能够生成新函数 了解函数之间传递信息的机制 介绍使用随机数产生器的模拟技术 了解标识符如何限于特定程序区域 如何编写和使用调用自己的函数3. 1简介解决实际问题的大多数程序都比前儿章介绍的程序要大得多。经验表明,要 开发和维护大程序,最好的办法是从更容易管理的小块和小组件开始。这种方法 称为“分而治之,各个击破"(divideand conquer) 本章介绍C+语言中的许 多关键特性,可以帮助设计、实现、操作和维护大程序。4. 2 C+程序组件C+中的模块称为函数(function)和类(class)。C+程序一般是将程序员编 写的新函数与C+标准库(standard 1 ibrary)中提供的预装函数组合而成的,通 常是将程序员编写的新类与各种类库中提供的预装类组合而成的。本章主要介绍 函数,第6章开始将详细介绍类。C+标准库提供了丰富的函数集合,可以进行常用数学计算、字符串操作、 字符操作、输人/输出、错误检查和许多其他有用的操作。这就使程序员的工作 更加轻松,因为这些函数提供了程序员需要的许多功能。C+标准库函数是在C+ 编程环境中提供的。编程技巧3.1要熟悉C+标准库提供的类和函数集合。软件工程视点3. 1不要事事从头做起。要尽可能利用C+标准库提供的函数而不是生成新函 数,从而减少程序开发时间。可移植性提示3. 1利用C+标准库提供的函教能使程序可移植性更强。性能提示3.1不要改写现有库程序以使其更有效,这些过程的性能通常已经是最优的。程序员可以通过编写函数定义程序中多处使用的特定任务,这些通常称为程序 员定义的函数(prograrmmer-def ined function) 定义函数的语句通常只写一 次,这些语句是其他函数无法访问的。通过函数调用(function call)来调用(invoke.即让其完成指定任务)函数。 函数调用指定函数名和提供被调用函数完成工作所需的信息作为参数L可以把 这种形式与管理的层次形式相比,老板(调用函数或调用者)要求工人(被调用函 数)完成任务并在任务完成之后返回(即报告)结果。老板函数并不知道工人函数 如何完成工作。工人又可能调用其他工人函数,这是老板所不知道的。稍后会介 绍这种隐蔽实现细节如何促进良好的软件工程。田3.1显示了 main函数以层次 方式和儿个工人函数通信。注意worker!是worker4和worker5的老板函数。函 数之间的关系也可能与图中所示的层次结构有所不同。3.3数学函数库数学函数库使程序员可以进行某些常见数学计算。我们这里用各种数学库函 数介绍函数概念。本书梢后会介绍C+标准库中的许多其他函数。调用函数时,通常写上函数名,然后是对括号,括号中写上函数参数(或 逗号分隔的参数表)。例如程序员可以用下列语句计算和打印900. 0的平方根:cout « sqrt(900. 0);执行这个语句时,数学库函数sqrt计算括号中所包含数字(900.0)的平方根。数 字900. 0是sqrt函数的参数。上述语句打印30osqrtd函数取double类型参数, 返回double类型结果。数学函数库中的所有函数都返回double类型结果。要使 用数学库函数,需要在程序中包含math, h头文件(这个头文件在新的C+标准库 中称为cmath) 常见编程错误3. 1使用数学库孙数而不包括math. h文件是个语法错误。程序中使用的每个标准库函数都应包括标准头文件。函数参数可取常量、变量或表达式。如果cl=13.、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. 0ceil(-9. 8)=-9.0cos(x)x(弧度)的余弦cos(0.0)=1.0exp(x)指数函数exexp(l. 0)=2. 71828exp 0)=7.38906fabs (x)x 的绝对值x>0, abs (x)=xx=0, abs (x)=0. 0 x<0, abs (x)=-xfloor(x) 将x取整为不大于x的最大整floor (9. 2)=9. 0floor (-9. 8)=10.0fmod(x, y)x/y的浮点数余数fmod(13. 657,2.333)=1.992log(x)X的自然对数(底数为e)log(2. 718282)=1.0log (7. 389056)=2.0loglO(x)x的对数(底数为10)log(10. 0)=1. 0log(100. 0)=2. 0pow(x, y)x的y次方(xy)pow(2, 7)=128pow(9,. 5)=3sin(x)x(弧度)的正弦sin(0. 0)=0sqrt (x)X的平方根sqrt (900. 0)=30. 0sqrt 0)=3. 0tan(x)x(弧度的正切tan (0. 0)=03. 4函数函数使程序员可以将程序模块化。函数定义中声明的所有变量都是局部变量 (local variable),只在所在的函数中有效。大多数函数有一系列参数,提供函 数之间沟通信息的方式。函数参数也是局部变量。软件工程视点3. 2在包含多个函数的程序中,main应实现为组函数调用,这些函数进行大 量的程序工作。将程序函数化的目的有儿个,“分而治之、各个击破”的方法使程序开发更 容易管理。另个目的是软件复用性(software reusability),用现有函数作为 基本组件,生成新程序。软件复用性是面向对象编程的主要因素。有了好的函数 命名和定义,程序就可以由完成特定任务的标准化函数生成,而不必用自定义的 代码生成。第三个目的是避免程序中的重复代码,将代码打包成函数使该代码可 以从程序中的多个位置执行,只要调用函数即可。软件工程视点3.1每个函数只限于完成一个定义良好的任务,函数名应有效地表达这个任务, 这样可以提高软件复用性。软件工程视点3. 4如果无法用简单名称表达函数的作用,则可能是定义的函数要完成的任务太 分散。通常应把这种函数分解为几个更小的函数。3.5函数定义前面介绍的每个程序都有一个main函数,调用标准库函数完成工作。现在 要考虑程序员如何编写自定义函数。考虑个程序,用自定义函数,square计算整数1到10的平方(如图3. 3)。1 / Fig. 3. 3: f ig03_03. cpp2 / Creating and using a progra er-defined function3 Sinclude <iostream. h>45 int square( int ); / function prototype(函数原型)67 int main()(S9 for ( in x = 1; x <= 10; x+ )10 cout« square ( x ) « ”;1112 cout « endl;13 return 0;14 1516 / Function definition(函数定义)17 int square ( int y )18 (19 return y * y;20 输出结果:1 491625 36496481100图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-1ist)(declarations and statements)函数名(function-name)是任何有效标识符,返回值类型(return-value-type) 是函数向调用者返回值的数据类型,返回值类型void表示函数没有返回值。不 指定返回值类型时默认为into常见编程错误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. cpp2 / Finding the maximum of three integers3 Sinclude <iostream. h>45 int maxi mum ( int, int, int ); / function prototype (函数原型)67 int main()8 (9 int a, b, c;1011 cout Enter three integers:12 cin » a » b » c;1314 /a, b and c below are arguments to15 / the maximum function call (函数调用)16 cout Maximum is: “ maximum( a, b, c ) « endl;1718 return 0;19 )2021 / function maximum definition22 / x, y and z below are parameters to23 / the maximum function definition24 int maximum( int x, int y, int z )25 (26 int max = x;273031 if z > max )32 max = z;3334 return max;35 )输出结果:Enterthreeintegers:228517Maximumis:85Enterthreeintegers:923514Maximumis:92Enterthreeintegers:451998Maximumis:98图3. 4自定义函数maximum3. 6函数原型C+的最重要特性之一是函数原型(function prototype)函数原型告诉编译 器函数名称、函数返回的数据类型、函数要接收的参数个数、参数类型和参数顺 序,编译器用函数原型验证函数调用。旧版C语言不进行这种检查,因此函数调用出错时,编译器可能无法发现错误。 这种调用可能造成致命执行时错误或非致命执行时错误,导致很难确认的逻辑错 误,函数原型能纠正这个缺陷。软件工程视点3. 8C+中要求函数原型。用#include预处理指令从相应库的头文件中取得标准库函数的函数原型。也可以用#include取得包含读者和小组成员使用的函数原 型的头文件。软件工程视点3. 9如果函数定义出现在程序中首次使用函数之前,则不需要函数原型,这时函 数定义就作为函数原型。图3. 4中maximum函数原型为:int maximum(int, int, int);这个原型表示maximum取三个int类型参数,返回int类型结果。注意这个函数 原型与maximum函数定义的首部相同,只是不包括参数名(x、y、z)。编程技巧3. 6许多程序置用函数原型中的参数名来说明函数,编译器将忽略这些名称。常见编程错误3.11忘记函数原型末尾的分号是个语法错误。函数原型中包括函数名和参数类型的部分称为函数签名(functionsignature)或签名(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 expression!,混合类型表达式中每个值的类型提升为表 达式中最高的类型(实际上是生成每个值的临时值并在表达式中使用,原值保持 不变)。提升的另个常见用法是在函数参数类型不符合函数定义中指定的参数 类型时。图3. 5显示了内部数据类型由高到低的顺序。数据类型long double double floatunsignedlong int(同 unsigned long)long int(同 long)unsignedint(同 unsigned)intunsignedshort int(同 unsigned short)short int(同 short)unsigned charshortchar图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头文件可以用下列指令:Sinclude “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>包含从磁盘文件输入输出到磁盘文件的函数原型。这个头文件的新版本为f stream标准库头文件说明<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函数产生到RAND_MAX之间的整数(这是stdlib. h>头文件中定义的符号 常量)。RAND_MAX的值至少应为32767,也就是两个字节(即16位)所能表示的最 大整数值。如果rand函数真的可以随机产生整数,则每次调用rand函数时, 到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的每 个数值大约都出现!000次。从程序输出可见,通过比例缩放和移动,可以利用rand函数真实地模拟投 骰子。注意程序用不到switch结构中提供的default case,但我们还是加上 default case»这是个良好的编程习惯。第4章数组将介绍如何把整个switch 结构转换成简单的单行语句。1 / Fig. 3. 7: f ig0307. cpp2 / Shifted, scaled integers produced by 1 + rand( ) % 63 Sinclude <iostream. h>4 Sinclude <iomanip. h>5 #include <stdlib. h>7 int main( )9 for( int i = 1: i <= 20; i +) 10 cout<< setw(10 ) << 1 +rand( ) % 6 );1112 if( i % 5 = 0 )13 cout << endl;14 1516 return 0;17 )输出结果:55355242555322151464图3. 7比例缩放和移动“rand()%6”产生的整数1 / Fig. 3. 8:fig03 08. cpp2 / Roll a six-sided die 6000 times3 Sinclude <iostream. h>4 #include <iomanip. h>5 #include <stdlib. h>67 int main()8( 9 int frequencyl = 0, frequency2 = 0,frequency3 = 0, frequency4 = 0, frequency5 = 0, frequency6 = 0, face;1011121314151617181920212223242526272829303132333435363738forf( int roll = 1; roll <= 6000; roll+ ) ace = 1 + rand( ) % 6;switch ( face ) case 1:+frequencyl;break;case 2:+frequency2;break;case 3:+frequency3;break;case 4:+frequency4;break;case 5:+frequeneyS;break;case 6:+frequency6;break;default;cout << ,zshould never get here!"39) 4041 cout << "Face" << setw 13 ) << "Frequency”42<<"n1"«setw(43<<"n2«setw(44<<"n3«setw(45<<"n4"«setw(46<<"n5"«setw(47<<"n6"«setw(13 ) « frequencyl13 ) « frequency213 ) « frequency313 ) « frequency413 ) « frequency513 ) « frequency6 « endl;48 49 return 0;50 )输出结果:Face Frequency1 98729843102949745100461022图3. 8模拟投骰子6000次测试与调试提示3. 1即使能确切保证程序没有缺陷,也应在switch结 构中用个default case来找到错误。再次执行图3. ?的程序得到:553552 42555322151464注意打印的数值顺序与上一次完全相同,怎么能算是随机数呢,其实,这种可重 复性是rand函数的个重要特性。调试程序时,这种可重复性提供了证明修改 后程序能正确工作的关键。rand函数实际上产生的是伪随机数(pseudo-randomnumber)。重复调用rand 函数产生一系列看上去是随机的数值,但每次执行程序时,这组数值本身是可重 复的。一旦程序进行彻底调试之后,就可以调整为在每次执行程序时产生不同的 随机数系列。这个过程称为随机化(randomizing),是用标准库函数srand完成 的。srand函数取个unsigned类型的整数参数并内嵌rand函数(即种子), 就可以在每次执行程序时产生不同的随机数系列。srand函数的使用如图3. 9所示。在这个程序中,我们使用数据类型 unsigned (unsigned int的缩写)。int值至少占内存的两个字节,可以存正值或 负值。unsignediht变量值也至少占内存的两个字节。2字节的unsigned int 只能取0到65535的非负值,4字节的unsignediht只能取0到4294967295的 非负值,srand函数取unsigned int值作参数。srand函数的函数原型在头文件 stdlibh>新 C+标准的 cstdlib)中。下面将程序运行儿次并观察结果。注意,只要提供不同的种子,即可在每次 执行程序时产生不同的随机数系列。1 / Fig. 3. 9: fig0309. cpp2 / Randomizing die-rolling program3 Sinclude <iostream. h>4 Sinclude <iomanip. h>5 Sinclude <stdlib. h>7 int main()8 9 unsigned seed;1011 cout << "Enterseed:"12 cin » seed;13 srand seed );1415 for ( int i = 1; i <= 10; i+ ) 16 cout « setw( 10 ) << 1 + rand( ) % 6;1718 if ( i % 5 = 0 )19 cout « endl;20 )2122 return 0;23 )输出结果:Enter seed: 671651456312Enter seed: 4324264325144Enter seed: 6716514图3. 9投骰子随机化程序如果不想每次输入种子值而随机化,则要用如下语句:srand( time ( 0 );使计算机通过时钟值自动取得种子值。time函数(上述语句中该函数的参数为0) 返回当前“日历时间”的秒数,将这个值转换为无符号整数值,作为随机数产生 器的种子。time函数的函数原型在time>(新C+标准的ctime)中。性能提示3. 2srand函数只要在程序中调用一次即可得到所需的随机化结果,多次调用是 多余的,会降低程序性能。由rand函数直接产生的值总是取值为:rand() RAND_MAX前面介绍了如何用个语句模拟投骰子,该语句如下所示:face=l+rand( ) % 6;总是对变量face指定1 face<6的整数(随机)。注意这个范围的宽度(即构 成该范围的连续整数的个数)为6并从1开始。从上述语句可以看出,范围宽度 是由求模运算符比例缩放rand的数值(6)确定的,开始值等于rand % 6中加进的 数值(即1)。可以将这个结果一般化,如下所示:n = a + rand( ) %b;其中a是位移值(等于所要的连续整数范围的开始值),b是比例因子(即由连 续整数构成的该范围的宽度)。练习中将介绍如何从组非连续整数中随机选择 整数。常见编程错误3. 16用srnd函数代替rand函数产生随机数是个语法错误,因为srnd函数不返 回值。3.9案例:机会游戏与enum简介个最常见的机会游戏是投骰子游戏,游戏规则如下:游戏者投两枚骰子,每个骰于有六面,这些面包含1、2、3、4、5、6个点。 投两枚骰于之后,计算点数之和。如果第一次投时的和为7或11,则游戏者获 胜。如果第一次投时的和2、3或12,则游戏者输,庄家赢。如果第次投时的 和为4、5、6、8、9或10,则这个和成为游戏者的点数。要想赢,就要继续投骰子,直到赚到点数。如果投七次之后还没有赚到点数, 则游戏者输。图3. 10中的程序模拟了投骰子游戏,图3. 11显示了儿个示例的执行结果。 1 / Fig. 3.10: fig03_10. cpp2 / Craps3 Sinclude <iostream. h>4 Sinclude <stdlib. h>5 #include <time. h>67 int rollDice( void ); / function prototype89 int main ()10 (11 enum statusCONTINUE, WON, LOST;12 int sum, myPoint;13 status gameStatus;1415 srand( time( NULL );16 sum = rollDice( );/ first roll of the dice1718 switch ( sum ) 19 case 1:20case 11:/ win on first roll2122232425262728293031323334353637383940