Presentation is loading. Please wait.

Presentation is loading. Please wait.

第4章 大型综合程序范例解析 前言 目的: 通过案例解析,领略大型程序的设计思想和开发方法 ,了解程序评价标准 案例: 通讯录 简单计算器

Similar presentations


Presentation on theme: "第4章 大型综合程序范例解析 前言 目的: 通过案例解析,领略大型程序的设计思想和开发方法 ,了解程序评价标准 案例: 通讯录 简单计算器"— Presentation transcript:

1 第4章 大型综合程序范例解析 前言 目的: 通过案例解析,领略大型程序的设计思想和开发方法 ,了解程序评价标准 案例: 通讯录 简单计算器
俄罗斯方块

2 第4章 大型综合程序范例解析 主要内容 通讯录范例解析 简易计算器范例解析 俄罗斯方块范例解析

3 第4章 大型综合程序范例解析 通讯录 问题描述: 以文件的方式保存用户录入的通讯录数据 供用户查询和使用通讯录信息

4 第4章 大型综合程序范例解析 通讯录 功能分析: 记录项的基本属性:姓名、性别、住址、联系电话、电子邮件 等 操作功能:
录入:操作添加一条新的记录项 删除:删除一条已经存在的记录项

5 第4章 大型综合程序范例解析 通讯录 功能分析: 修改:改变记录项的一个或多个属性,并用新的记录项覆盖已经存在的记录项
查找:根据用户输入的属性值查找符合条件的记录项。

6 第4章 大型综合程序范例解析 通讯录 功能分析:
通讯录数据以文件形式存储在磁盘上,根据实际需要定义文件的存储格式;在程序运行中需要对文件进行读取操作。 程序中还要对输入数据的容错性进行检查,可以保证通讯录数据的合法性。

7 第4章 大型综合程序范例解析 通讯录 设计: 程序总体结构: 输入输出模块:人机交互,包括程序界面显示、用户输入响应、结果输出等
管理模块:管理模块从输入输出模块读取用户命令并进行相应的操作,包括录入、删除、修改、查找、列表等 文件操作模块:进行存储文件的读写

8 第4章 大型综合程序范例解析 输入输出终端 输入输出模块 管理模块 文件操作模块 存储文件 通讯录 模块结构图 用户输入 系统输出 文件读出
文件写入 存储文件

9 第4章 大型综合程序范例解析 通讯录 界面设计 :

10 第4章 大型综合程序范例解析 通讯录 数据结构设计: struct myrecord{ unsigned int num;
unsigned int group; char name[MAXLEN+1]; char gender; date birthday; char address[MAXLEN+1]; char phone[MAXLEN+1]; char [MAXLEN+1]; };

11 第4章 大型综合程序范例解析 通讯录 数据结构设计: struct mydate{ unsigned int year;
unsigned int month; unsigned int day; }; typedef struct mydate date;

12 第4章 大型综合程序范例解析 通讯录 数据结构设计: 三个查询关键字:记录编号、组别和联系人姓名 union mysearch_entry{
unsigned int num; unsigned int group; char name[MAXLEN+1]; }; typedef union mysearch_entry search_entry;

13 第4章 大型综合程序范例解析 通讯录-函数设计 menu.c输入输出文件 void menulist(void)
函数原型 函数功能 函数处理描述 void menulist(void) 以文本方式显示程序主菜单,同时响应用户输入 调用bioske(0),获取按键的值 void upbar(int y) 向上滚动光标条 通过改变字体颜色实现光标条移动 void downbar(int y) 向下滚动光标条 void mydelay(void) 等待用户响应 调用getch()实现 void format(void) 结果输出时打印输出的格式信息 调用printf()实现 void searchmenu(void) 输出查询功能的子菜单 void input_search(char ch) 处理查询时用户的输入,将关键字读入 根据输入参数ch,执行相应的操作 int input_num(void) 读入一个整型数值(记录编号),进行合法性检查 采用了递归的方法循环读取数据 int input_new(myrecord *p) 进行数据修改时,读入一个新的记录项,并用它覆盖输入参数所指向的数据记录项。 参数:新记录项的指针 返 回 值:返回是否进行了修改的信息,已修改返回 ,否则返回0。 myrecord *input_app(void) 录入信息时处理键盘输入,对输入进行合法性检查 逐项录入通讯记录 int date_legal(int year,int month,int day) 检查日期是否为合法 参数:年、月、日的信息 返 回 值:合法日期返回1,否则返回0

14 第4章 大型综合程序范例解析 通讯录-函数设计 file.c文件处理文件 int file_app(myrecord *p)
添加一条新的记录项 参 数:要录入的记录项的指针 返 回 值:操作结果(插入成功返回1,失败返回0) myrecord *read_record(int n) 从文件中读出下标为n的块(记录项) 参 数:下标值 返 回 值:读取结果的指针 int write_record(myrecord *p,int n) 向文件中写入某一块(如果该块已经存在,将进行覆盖) 参 数:指向记录项的指针和要写入的块位置 int file_search(search_entry *s,int f) 对存储文件进行遍历,查找符合输入的记录项并输出 参 数:指向查询项的指针和查询类型 返 回 值:符合条件的记录项总数(如果是0则查找失败) int file_delete(int n) 删除文件中某个记录块

15 第4章 大型综合程序范例解析 通讯录-函数设计 control.c控制文件 void append(void) 执行数据录入操作
调用input_app()完成数据录入,调用file_app()完成数据保存。 void delet(void) 执行数据记录项删除操作 调用file_search查找要删除的记录,然后调用file_delete()进行删除 void search(void) 执行数据查找操作 调用searchmenu()进入查找的菜单,调用input_search(ch)获得要查找的内容,file_search()进行查找 void change(void) 执行数据记录项修改操作 调用input_num()输入待修改的记录,调用file_search()进行查找,调用input_new()输入新的内容,调用write_record()进行更新 void list_all(void) 列出当前所有联系人信息 打开文件,遍历所有记录并输出 void init(void) 系统初试化操作,保证文件的正确性和合法性 调用fopen()打开文件,初始化 void quit(void) 系统退出函数,写回文件以保证数据的一致性 关闭文件,退出系统

16 第4章 大型综合程序范例解析 通讯录-程序运行示意图

17 第4章 大型综合程序范例解析 通讯录 源程序:

18 第4章 大型综合程序范例解析 主要内容 通讯录范例解析 简易计算器范例解析 俄罗斯方块范例解析

19 第4章 大型综合程序范例解析 简单计算器 问题描述:
Windows操作系统提供了计算器应用程序,它有标准型和科学型两种模式,是标准的Windows图形界面应用程序,支持鼠标和键盘操作。 Windows提供的计算器

20 第4章 大型综合程序范例解析 简单计算器 功能分析: 简单计算器是对Windows计算器的模拟,设计其功能如下:

21 第4章 大型综合程序范例解析 简单计算器 设计:
简单计算器的处理过程:首先进行图形和鼠标初始化,接着显示简单计算器外观,并接受用户的鼠标控制使用。如果单击了鼠标右键,则程序关闭图形方式并结束运行。

22 第4章 大型综合程序范例解析 简单计算器 主程序流程: void main() { GraphInit(); initmouse();
picture(); compute (); closegraph(); } 简单计算器的流程图

23 第4章 大型综合程序范例解析 简单计算器 界面外观 :

24 第4章 大型综合程序范例解析 简单计算器 界面设计: (1)背景采用浅蓝色,用灰色作底色和红色作前景色画一个bar3d图形,模拟立体效果;
(4)在每个按钮框上显示相应的按钮标签; (5)在简单计算器下方输出使用说明和设计单位信息。

25 第4章 大型综合程序范例解析 简单计算器 数据结构设计:
简单计算器没有用到复杂的数据结构,计算时定义了两个double变量u、v和一个字符数组s及几个标志变量。开始使用时u和v变量分别存储第1次和第2次输入的数据,计算结果始终保存在u中。继续运算时,输入的数据存于v,并与u中的数据运算后结果保存于u中。

26 第4章 大型综合程序范例解析 简单计算器 数据结构设计: 简单计算器进行加减乘除运算的函数compute()中,定义以下主要标志变量:
(1) sign:表示'+'、'-'、'*'、'/'等运算符的整数变量。值为0表示当前未单击过运算符。 (2) flag:输入数据时是否单击了小数点。单击了小数点,flag为1,否则为0。

27 第4章 大型综合程序范例解析 简单计算器 函数设计:
简单计算器采用了结构化程序设计思想,由一个.h文件和四个.c文件组成,并构造了TC工程文件来管理和生成简单计算器应用。每个源文件包含多个函数的设计,这些函数的功能设计及处理描述见下表。

28 第4章 大型综合程序范例解析 简单计算器-函数设计 文件名 函数原型 函数功能 处理描述 mouse.c void initmouse()
鼠标初始化 调用0x33中断的0号功能 寄存器ax返回值不是-1,表明鼠标初始化失败 void get_mouse_position (int *x,int *y) 获取鼠标位置坐标 调用0x33中断的3号功能 鼠标位置存于寄存器cx和dx中,然后存于x、y指针变量指向的单元返回调用函数 int leftpress() 判断鼠标左键是否单击 鼠标状态存于寄存器bx,其第0位是1表明左键被按下 rightpress() 判断鼠标右键是否单击 鼠标状态存于寄存器bx,其第1位是1表明右键被按下

29 第4章 大型综合程序范例解析 简单计算器-函数设计 picture.c void picture() 绘制计算器界面
使用图形函数绘制计算器外框 调用公用函数bottonup()绘制弹起效果的按钮 调用系统outtextxy()输出按钮标签 调用系统outtextxy()输出使用说明等信息 注: 函数开始绘制鼠标图标并保存在全局变量imagep中,在compute()函数(见compute.c文件)中涉及显示、移动鼠标等操作

30 第4章 大型综合程序范例解析 简单计算器-函数设计 util.c void GraphInit() 图形初始化
调用系统函数initgraph()进行初始化 失败则程序结束运行 bottondown (int x,int y) 画按下效果的按钮框 调用画线及颜色设置函数绘制按下效果的按钮框 (x,y)表示按钮框的左上角坐标 bottonup(int x,int y) 画弹起效果的按钮框 调用画线及颜色设置函数绘制弹起效果的按钮框 show(int x,int y) 单击按钮的效果显示 显示按下的按钮 延时 显示弹起的按钮 注: 模拟按钮被单击

31 第4章 大型综合程序范例解析 简单计算器-函数设计 util.c char getnumber (int x,int y) 获取单击按钮图标
每个按钮的位置是确定的(即矩形框的左上角坐标和大小已知) 根据单击按钮时鼠标的(x,y)可确定单击了哪个按钮,函数返回按钮的标签 例: 左上角坐标为(150,105)和右下角为(200,135)的矩形框表示计算器上数字'7'按钮 void clearscreen() 清信息显示框 清除信息显示框中的数据(可能是输入的数或输出的计算结果) int kx(char d) 获取按钮的左上角x坐标 d表示按钮的图标 根据d返回按钮的左上角x坐标 按钮左上角坐标为模拟单击按钮服务

32 第4章 大型综合程序范例解析 简单计算器-函数设计 util.c int ky(char d) 获取按钮 的左上角 y坐标 d表示按钮的图标
按钮左上角坐标为模拟单击按钮服务 void outch(double sum) 在信息显 示框中输 出sum sum的绝对值大于1e20,输出E,即对太大或太小的数显示出错 sum小于等于1e20且大于等于1e8,显示格式为d.dExx sum大于等于-1e20且小于等于-1e8,显示格式为-d.dExx sum的值在-1e8和1e8之间,若是0,显示0. 其他,按实际显示

33 第4章 大型综合程序范例解析 简单计算器-函数设计 compute.c void compute() 简单计算器的主处理函数
最外层循环由鼠标右键控制,单击右键则计算器退出 在其内层,判断鼠标左键是否单击,无则仅做移动鼠标光标处理 若单击左键,且MouseLeftFlag全局变量为1,则置该变量为0,避免重复进入,并进行相应处理 若单击的是'C',则启用计算器 若单击'0'-'9'数字键,则进行第1个或第2个输入数据的处理 若单击加,减,乘,除,等号按钮,进行相应的计算处理 若单击小数点按钮的处理 若单击求平方根按钮的处理 若单击+/-按钮的处理 double calculate(double u, double v,int sign) 加减乘除计算处理 根据sign的运算符进行加减乘除的计算处理 计算结果保存在u中,但由函数返回 main() 计算器的main()函数 应用程序由多个文件组成时,仅能有一个main()函数

34 第4章 大型综合程序范例解析 简单计算器 源程序:

35 第4章 大型综合程序范例解析 简单计算器 测试:
关于测试方法和特殊输入的测试,针对简单计算器程序,我们可以从以下几个方面来检验程序功能是否正确。 1.界面及按钮单击测试 检查界面布局是否合理、正确,单击按钮是否有按下再弹起效果,单击按钮的输入是否正确。

36 第4章 大型综合程序范例解析 简单计算器 测试: 2.简单计算器的功能测试 (1) 加、减、乘、除四则运算的测试。 (2) 优先级处理的测试
(1) 加、减、乘、除四则运算的测试。 (2) 优先级处理的测试 单击‘1’、‘+’、‘2’、‘* ’、‘4’、‘=’按钮,结果是12,即不支持四则运算的优先级。因为单击‘*’按钮时,1+2的结果3已经计算并显示在信息显示框中,此时继续计算乘4得结果12。

37 第4章 大型综合程序范例解析 简单计算器 测试: (3) 求平方根运算的测试 1)计算sqrt(9)
(3) 求平方根运算的测试 1)计算sqrt(9) 先单击'9'、再'S'按钮,看结果是否正确。 2)计算1+sqrt(9) 检查是否能正确1+sqrt(9)。 通过以上测试可以基本确定计算器程序是否实现了预定的功能。

38 第4章 大型综合程序范例解析 主要内容 通讯录范例解析 简易计算器范例解析 俄罗斯方块范例解析

39 第4章 大型综合程序范例解析 俄罗斯方块 问题描述:
要求支持键盘操作和7种不同类型方块的旋转变换,并且界面上显示下一个方块的提示以及当前的玩家得分

40 第4章 大型综合程序范例解析 俄罗斯方块 功能分析: 俄罗斯方块游戏需要解决的问题包括: ( 1)整个游戏界面的图形显示;
(2)各种方块形状的表示; (3)如何控制方块的移动、旋转和下落速度; (4)如何判断方块是否到底; (5)如何判断一行是否填满以及如何消去填满的行; (6)如何判断游戏的结束及如何终止游戏; (7)游戏难度的设计和得分规则

41 第4章 大型综合程序范例解析 俄罗斯方块 功能分析: 重点: 游戏面板的数据结构 :二维数组
7种形状方块的数据结构 :结构体保存每种形状方块的坐标、颜色

42 第4章 大型综合程序范例解析 俄罗斯方块 设计: 程序总体结构: void main() { InitializeGraph();
SetTimer(newtimer); /*设置新的时钟中断*/ while(1) { StartGame(); ProcessInGame(); if(bOver) break; } KillTimer(); closegraph();

43 第4章 大型综合程序范例解析 俄罗斯方块 界面设计 : 分为左右两个部分: 左边为游戏面板 右边有三个框:下一形状提示框、速度框和记分框

44 第4章 大型综合程序范例解析 俄罗斯方块 数据结构设计: 定义如下的结构体来表示每一个形状: struct block{
int arrXY[8]; int nColor; int nNext; }; 可用4*4的格子显示7种形状,并用4个数对来表示: arrXY [0]、arrXY [1]表示第一个数对,arrXY [2]、arrXY [3]表示第二个数对 …。 例如, (-2,0)、(-1,0)、(0,0)、(1,0) 表示左边的方块 -3□□□□ -2□■□□ -1□■□□ 0 □■■□

45 第4章 大型综合程序范例解析 俄罗斯方块 数据结构设计: 每一种形状都可以进行旋转,旋转后的变形体同样可用结构体block表示。
所有的7种形状和它们的旋转体(共19个)可保存在一个全局数组arrayBlock中。 Block中的nNext就是当前形状逆时针旋转后的下一个形状在该全局数组中的索引。

46 第4章 大型综合程序范例解析 俄罗斯方块 数据结构设计: 第一个形状和它的旋转体在arrayBlock中的表示
□□□□ □□□□ □□□□ □□□□ □■□□ □□□□ □■■□ □□□□ □■□□ □□■□ □□■□ ■■■□ □■■□ ■■■□ □□■□ ■□□□ BLOCK arrayBlock[19]={ /*x1,y1,x2,y2,x3,y3,x4,y4, color, next,第一种形状*/ { 0,-2, 0,-1, 0, 0, 1, 0, CYAN, 1}, /*第一种形状,对应图3-12的第一个*/ {-1, 0, 0, 0, 1,-1, 1, 0, CYAN, 2}, /*一种旋转体,对应图3-12的第二个*/ { 0,-2, 1,-2, 1,-1, 1, 0, CYAN, 3}, /*另一种旋转体,对应图3-12的第三个*/ {-1,-1,-1, 0, 0,-1, 1,-1, CYAN, 0}, /*第三种旋转体,对应图3-12的第四个*/ ……. }

47 第4章 大型综合程序范例解析 俄罗斯方块 数据结构设计: 游戏的主界面:宽10、高20的游戏板
数据结构:全局数组Gameboard[12][22], 1表示已有方块,0表示这个位置空着。在10*20基础上各加2行、2列为了便于判断形状在移动时是否到边、到底。 整个屏幕的坐标系原先为640*480。在此游戏中,将16个像素定义为一个方格的边长,所以坐标系转变成为了40*30(640/16=40,480/16=30)。

48 第4章 大型综合程序范例解析 俄罗斯方块 数据结构设计: 绝对坐标和相对坐标的转换 相对坐标即指在结构体block中的4对坐标
某个形状的绝对坐标:指原点方块(4*4格子中的第2列、第4行的方块)在10*20的游戏面板中的坐标

49 第4章 大型综合程序范例解析 俄罗斯方块-程序结构 1个.h文件和4个.c文件,共20个函数; 函数相互关系见右图

50 第4章 大型综合程序范例解析 俄罗斯方块-函数设计 Timer.c文件 文件名 函数原型 函数功能 函数处理描述 Timer.c
Void interrupt (*oldtimer)(void) 指向原来时钟中断处理过程入口的中断处理函数指针(句柄) Void interrupt newtimer(void) 新的时钟中断处理函数 调用(*oldtimer)()函数句柄,计时器自加1 Void SetTimer(void interrupt(*IntProc)(void)) 设置新的时钟中断处理过程 调用setvect()设置新的时钟中断处理过程 void KillTimer() 恢复原有的时钟中断处理过程 调用setvect()恢复原有的时钟中断处理过程

51 第4章 大型综合程序范例解析 俄罗斯方块-函数设计 Drawing.c文件 文件名 函数原型 函数功能 函数处理描述 Drawing.c
void InitializeGraph() 初始化图形模式 ①调用initgraph()切换到图形模式 ②初始化若发生错误,则返回错误码。 Void InitializeGameboard() 初始化游戏面板以及下一形状提示框、计分框和难度框 ①调用bar()、rectangle()等库函数绘图函数绘制游戏界面。 ②调用outtextxy()函数显示文字。

52 第4章 大型综合程序范例解析 俄罗斯方块-函数设计 Util.c文件 函数原型 函数功能 函数处理描述 Util.c
void DrawSquare(int x, int y) 在坐标(x, y)处画方块 调用库函数bar()绘制方块 Void DrawBlock(int BlockIndex, int sx, int sy,int color) 在坐标(sx, sy)处绘制颜色为color的形状 调用DrawSquare()函数绘制形状 Int IsConflict(int BlockIndex, int x, int y) 判断形状是否能存在于坐标(x, y)处 无冲突返回0,有冲突返回1 Void HandleLeft(int BlockIndex,int *x, int *y) 按下左方向键时的处理函数 调用IsConflic()函数判断形状是否可以左移, Void HandleRight(int BlockIndex,int *x, int *y) 按下右方向键时的处理函数 调用IsConflic()函数判断形状是否可以右移, Void HandleUp(int *BlockIndex,int *x, int *y) 按下上方向键(旋转键)时的处理函数 调用IsConflic()函数判断形状是否可以旋转, int HandleDown(int BlockIndex,int *x, int *y) 按下向下方向键或自由下落时的处理函数 形状在自由下落返回0,无法下落了返回1,并做相应处理 int IsLineFull(int y) 判断第y行是否已被填满 填满返回1,否则返回0 void KillLine(int y) 消去第y行 将消去的行置为背景色 int KillLines(int y) 消去第y行以及与第y行连续的上面被填满的行 返回消去的行数 int IsGameOver() 判断游戏是否结束 游戏结束返回1,否则返回0 int GameOver() 在界面上输出游戏结束信息,并根据用户按键选择决定是否退出游戏 退出游戏返回1,否则返回0

53 第4章 大型综合程序范例解析 俄罗斯方块-函数设计 Russia.c文件 文件名 函数原型 函数功能 函数处理描述 Russia.c
void StartGame() 游戏开始时调用的函数 ①绘制界面需调用函数InitializeGameboard()②接下来初始化游戏面板的各个方块和一些全局变量的初值。 void ProcessInGame() 处理在游戏中的各种事件(如按下各种按键)等 调用HandleUp()、HandleDown()、HandleLeft()、HandleRight()等事件处理函数 void main() 主流程函数 主函数入口

54 第4章 大型综合程序范例解析 俄罗斯方块—重要函数算法分析
IsConfilict(int ,int,int):判断索引号为ShapeIndex的形状在坐标(x,y)是否与游戏板当前状态发生冲突: int IsConflict(int BlockIndex, int x, int y) { int i; /* 对组成索引号为ShapeIndex的形状的四个方块依次判断 */ for (i=0;i<=7;i++,i++) { /* 如果四个方块中有任何一个方块的x坐标小于1或大于10,表示超出左边界或右边界。此时,发生冲突 */ if(arrayBlock[BlockIndex].arrXY[i]+x<1||arrayBlock[BlockIndex].arrXY[i]+x>10) return TRUE; /* 如果四个方块中某个方块的y坐标小于1,表示整个形状还没有完全落入游戏板中。此时,没有必要对这个方块进行判断。*/ if (arrayBlock[BlockIndex].arrXY[i+1]+y<1) continue; /* 如果四个方块中有任何一个方块与游戏板当前状态发生冲突,则整个形状在(x,y)处与游戏板当前状态冲突 */ if( Gameboard[arrayBlock[BlockIndex].arrXY[i]+x][arrayBlock[BlockIndex].arrXY[i+1]+y]) } /* 四个方块中没有任何一个方块与游戏板当前状态发生冲突,则整个形状在(x,y)处没有与游戏板当前状态冲突 */ return FALSE;

55 第4章 大型综合程序范例解析 俄罗斯方块 源程序:


Download ppt "第4章 大型综合程序范例解析 前言 目的: 通过案例解析,领略大型程序的设计思想和开发方法 ,了解程序评价标准 案例: 通讯录 简单计算器"

Similar presentations


Ads by Google