- 结构化程序设计
- 结构化程序设计
- 枚举类型与头文件
- 枚举类型
- 头文件
- 石头剪子布游戏完整程序
- 库与预处理
- 设计自己的库
- 随机函数库的设计与实现
- 随机函数库的应用
设计阶段
自顶向下的分解,每个小问题设计为一个函数,公共小问题可以设计成一个库
实现阶段
自底向上的实现
程序由3种基本结构组成
- 顺序
- 分支
- 循环
类型定义格式
enum 枚举类型名 {元素表};
石头、剪子、布中的枚举类型
- 用户输入值的类型:enum p_r_s { paper, rock, scissor, game, help, quit } ;
- 比较结果类型:enum outcome { win, lose, tie } ;
枚举类型变量的定义
p_r_s select;
枚举类型变量的使用 - 赋值: select = paper;
- 比较:paper < rock 比较这两个值的内部表示
- 枚举类型不能直接输入输出
枚举类型的内部表示 - 采用编码表示:默认用0代表pape, 1代表rock ,…,5 表示quit
- 指定编码值
- 希望从1而不是0开始编号,可以这样定义enum p_r_s { paper = 1, rock, scissor, game, help, quit } ;
- 可以从中间某一个开始重新指定,如enum p_r_s { paper, rock = 5, scissor, game, help, quit } ;
enum studentNum{1001, 1002, 1003, 1004}是不合法的枚举常量,因为大括号{}中是一个用逗号分隔的标识符列表。标识符由字母(A-Z,a-z)、数字(0-9)、下划线“_”组成,并且首字符不能是数字。
头文件- 包含所有的符号常量定义、类型定义和函数原型声明
- 每个模块都include这个头文件
- 链接时,编译器会发现这些类型定义、符号常量和函数原型的声明在程序中反复出现多次
- 解决方法 需要用到一个新的编译预处理命令:
#ifndef 标识符 … #endif
头文件实现格式
#ifndef _name_h
#define _name_h
头文件真正需要写的内容
#endif
石头、剪刀、布游戏的头文件
// 文件:p_r_s.h // 本文件定义了两个枚举类型,声明了本程序包括的所有函数原型 #ifndef P_R_S #define P_R_S #include#include #include using namespace std; enum p_r_s { paper, rock, scissor, game, help, quit }; enum outcome { win, lose, tie }; outcome compare(p_r_s player_choice, p_r_s machine_choice); void prn_game_status(); void prn_help(); void report(outcome result); p_r_s selection_by_machine(); p_r_s selection_by_player(); #endif
- 在cpp文件内include自定义的头文件,例如myMath.h,则代码是:#include "myMath.h"
- c++支持将cpp实现代码混入头文件中,来简化代码编写,c++程序的头文件后缀名是.hpp
- 在头文件.h中如果要声明一个int型变量x,需要在代码int x;之前添加 extern关键字,并在.cpp文件中定义int x;
主模块的实现
// 文件:main.cpp
// 石头、剪子、布游戏的主模块
#include "p_r_s.h"
int main()
{
outcome result;
p_r_s player_choice, machine_choice;
// seed the random number generator
srand(time(NULL));
while ((player_choice = selection_by_player()) != quit)
switch (player_choice)
{
case paper:
case rock:
case scissor:
machine_choice = selection_by_machine();
result = compare(player_choice, machine_choice);
report(result);
break;
case game:
prn_game_status();
break;
case help:
prn_help();
}
prn_game_status();
return 0;
}
Select模块的实现
//文件:select.cpp
//包括机器选择selection_by_machine和玩家选择selection_by_player函数的实现
#include "p_r_s.h"
p_r_s selection_by_machine()
{
int select = (rand() * 3 / (RAND_MAX + 1));
cout << " I am ";
switch (select)
{
case 0:
cout << "paper. ";
break;
case 1:
cout << "rock. ";
break;
case 2:
cout << "scissor. ";
break;
}
return ((p_r_s)select);
}
p_r_s selection_by_player()
{
char c;
p_r_s player_choice;
prn_help();
cout << "please select: ";
cin >> c;
switch (c)
{
case 'p':
player_choice = paper;
cout << "you are paper. ";
break;
case 'r':
player_choice = rock;
cout << "you are rock. ";
break;
case 's':
player_choice = scissor;
cout << "you are scissor. ";
break;
case 'g':
player_choice = game;
break;
case 'q':
player_choice = quit;
break;
default:
player_choice = help;
break;
}
return player_choice;
}
Compare模块的实现
//文件:compare.cpp
//包括compare函数的实现
#include "p_r_s.h"
outcome compare(p_r_s player_choice, p_r_s machine_choice)
{
outcome result;
if (player_choice == machine_choice)
return tie;
switch (player_choice)
{
case paper:
result = (machine_choice == rock) ? win : lose;
break;
case rock:
result = (machine_choice == scissor) ? win : lose;
break;
case scissor:
result = (machine_choice == paper) ? win : lose;
}
return result;
}
Print模块的实现
//文件:print.cpp
//包括所有与输出有关的模块。
//有prn_game_status,prn_help和report函数
#include "p_r_s.h“
static int win_cnt = 0, lose_cnt = 0, tie_cnt = 0; //模块的内部状态
void report(outcome result)
{
switch (result)
{
case win:
++win_cnt;
cout << "You win. n";
break;
case lose:
++lose_cnt;
cout << "You lose.n";
break;
case tie:
++tie_cnt;
cout << "A tie.n";
break;
}
}
void prn_game_status()
{
cout << endl;
cout << "GAME STATUS:" << endl;
cout << "win:" << win_cnt << endl;
cout << "Lose:" << lose_cnt << endl;
cout << "tie:" << tie_cnt << endl;
cout << "Total:" << win_cnt + lose_cnt + tie_cnt << endl;
}
void prn_help()
{
cout << endl
<< "The following characters can be used:n"
<< " p for papern"
<< " r for rockn"
<< " s for scissorsn"
<< " g print the game statusn"
<< " h help, print this listn"
<< " q quit the gamen";
}
库与预处理
设计自己的库
库的概念
- 库:常用的工具
- 库的主题:同一个库中的函数都应该是处理同一类问题,自己设计的库也要有一个主题
- 库的通用性:在某一应用程序中提取库内容时应尽量考虑到兼容更多的应用,使其他应用程序也能共享这个库
库的设计和实现
- 设计库的接口:库的用户必须了解的内容,包括库中函数的原型、这些函数用到的符号常量和自定义类型,接口表现为一个头文件
- 设计库中的函数的实现:表现为一个源文件
- 库的这种实现方法称为信息隐藏
1.库功能
- 生成low到high之间的随机数: int RandomInteger(int low, int high)
- 初始化函数:RandomInit()实现设置随机数种子的功能
2.接口文件
- 头文件的格式
#ifndef _name_h #define _name_h 头文件真正需要写的内容 #endif
- 注释 头文件头上有段注释,说明库的主题、功能。每个函数声明前有一段注释,告诉用户如何使用这些函数
3.随机函数库接口文件
//文件:Random.h //随机函数库的头文件 #ifndef _random_h #define _random_h //函数:RandomInit //用法:RandomInit() //作用:此函数初始化随机数种子 void RandomInit(); //函数:RandomInteger //用法:n = RandomInteger(low, high) //作用:此函数返回一个 low 到 high 之间的随机数,包括 low 和 high int RandomInteger(int low, int high); #endif
4.库的实现
- 实现文件名:与头文件的名字是相同
- 实现文件的格式
- 注释(这一部分简单介绍库的功能)
- include此cpp文件所需的头文件
- 每个实现要包含自己的头文件,以便编译器能检查函数定义和函数原型声明的一致性
- 每个函数的实现代码(在每个函数实现的前面也必须有一段注释)
5.随机函数库实现文件
//文件:Random.cpp //该文件实现了Random库 #include#include #include "Random.h" //函数:RandomInit //该函数取当前系统时间作为随机数发生器的种子 void RandomInit() { srand(time(NULL)); } // 函数:RandomInteger // 该函数将0到RAND_MAX的区间的划分成high - low + 1 个 子区间。当产生的随机数落在第一个 // 子区间时,则映射成low。 当落在最后一个子区间时,映射成high。当落在第 i 个子区间时 //(i 从 0 到 high-low),则映射到low + i int RandomInteger(int low, int high) { return (low + (high - low + 1) * rand() / (RAND_MAX + 1)); }
6.统计学函数库接口文件
//文件:statistics.h //统计学函数库 #ifndef _statistics_h #define _statistics_h //函数:Average //用法:double ave = Average(double*, double*) //作用:计算从数组中所有实数的算数平均值 double Average(double *begin, double *end); //函数:MinMax //用法:MinMax(double *, double *, double &, double &) //作用:统计数组的最小最大值,并且通过引用传参得到结果 void MinMax(double *begin, double *end, double &Min, double &Max); //函数:Median //用法:double med = Median(double*, double*) //作用:计算从数组中所有实数的中位数 double Median(double *begin, double *end); //函数:Mode //用法:double mod = Mode(double*, double*) //作用:计算从数组中所有实数的众数 double Mode(double *begin, double *end); #endif随机函数库的应用
将龟兔赛跑的模拟问题划分成主模块、移动模块、输出模块分别处理,是运用了自顶向下分解的设计思路。
使用程序员自己定义的库函数的时候,需要在使用之前include本地头文件.h文件,并且编译时需要将主程序与库函数的实现文件.cpp文件链接起来
主模块
#include "Random.h" //包含随机数库 #includeusing namespace std; const int RACE_END = 70; //设置跑道的长度 int move_tortoise(); int move_hare(); void print_position(int, int, int); int main() { int hare = 0, tortoise = 0, timer = 0; RandomInit(); //随机数初始化 cout << "timer tortoise haren"; //输出表头 while (hare < RACE_END && tortoise < RACE_END) { tortoise += move_tortoise(); //乌龟移动 hare += move_hare(); //兔子移动 print_position(timer, tortoise, hare); ++timer; } if (hare > tortoise) cout << "n hare wins!n"; else cout << "n tortoise wins!n"; return 0; }
移动模块
// 文件名:move.cpp
#include "Random.h" //本模块用到了随机函数库
int move_tortoise()
{
int probability = RandomInteger(0, 9); //产生0到9之间的随机数
if (probability < 5)
return 3; //快走
else if (probability < 7)
return -6; //后滑
else
return 1; //慢走
}
int move_hare()
{
int probability = RandomInteger(0, 9);
if (probability < 2)
return 0; //睡觉
else if (probability < 4)
return -9; //大后滑
else if (probability < 5)
return 14; //快走
else if (probability < 8)
return 3; //小步跳
else
return -2; //慢后滑
}
Print模块
// 文件名:print.cpp #includeusing namespace std; void print_position(int timer, int t, int h) { if (timer % 6 == 0) //每隔6秒空一行 cout << endl; cout << timer << 't' << t << 't' << h << 'n'; }



