文章目录

  • 前言
  • 系统需求分析和注意事项
  • 具体实现(链表基本操作)
    • model.h
    • AMS.cpp
    • cardList.cpp
      • CardListInit()
      • addNewCard()
      • displayCard()
      • cardIsExist()
    • service.cpp
      • addCard()
      • clearData()
  • 具体实现(上机下机功能)
    • model.h
    • AMS.cpp
    • billList.cpp
      • BillListInit()
      • shangJi()
      • Logon()
      • updateCard()
      • saveBilling()
      • xiaJi ()
      • settle()
      • getAmount()
      • billingIsExist ()
      • updateBilling()
  • 总结

前言

第4次:改写第3次实验内容
文件 <-> 链表<-> 系统的操作
第5-7次:在第4次实验基础上,完成全部功能,是基于链表的

系统需求分析和注意事项

详情可参考前一篇文章:
传送门:武汉理工大学计算机基础与编程综合实验——网吧计费管理系统第一个版本


以下是本篇文章正文内容,下面案例可供参考

具体实现(链表基本操作)

model.h

定义卡信息链表结点类型。

struct CardNode
{Card data;//结点数据struct CardNode* next;//指向下个结点的指针
}

AMS.cpp

定义链表表头指针。

CardNode* pCardNodeHead=NULL;
pCardNodeHead=CardListInit(CARDPATH);

cardList.cpp

CardListInit()

为了对比容器 vector 和链表 list 的操作,我们使用 cardList.cpp 和 cardList.h 文件来存放对卡 card 的基本操作。

CardNode* CardListInit(const string cardFilename)
{ifstream cardfile(cardFilename);CardNode *pCardNode, *pCardNodeHead, *pCardNodeTail;Card card;if(!cardfile.is_open()){return NULL;}
pCardNodeHead = NULL;
pCardNodeTail = NULL;while(1){cardfile.read((char*)&card, sizeof(Card));if(cardfile.eof()){break;}pCardNode = new CardNode;pCardNode->data = card;if(pCardNodeHead == NULL){pCardNodeHead = pCardNode;pCardNodeTail = pCardNode;}else{pCardNodeTail->next = pCardNode;pCardNodeTail = pCardNode;}}pCardNodeTail->next = NULL;cardfile.close();
return pCardNodeHead;
}

addNewCard()

int addNewCard(string strNo, string strPwd, float fBalance, CardNode**
ppCardNodeHead)
{int nCardIndex=0;if(cardIsExist(strNo, nCardIndex, *ppCardNodeHead) != NULL){return FINDCARD;}Card card;strcpy(card.aName, strNo.c_str());strcpy(card.aPwd, strPwd.c_str());card.fBalance = fBalance;
// 添加新卡时,累计金额等于开卡金额card.fTotalUse = card.fBalance;
card.nStatus = UNUSE; // 卡状态
card.nUseCount = 0; // 使用次数
// 开卡时间,最后使用时间都默认为当前时间
card.tStart = card.tLast = time(NULL);
CardNode* pCardNode = new CardNode;
pCardNode->data = card;
CardNode *pCardNodeHead=*ppCardNodeHead;
CardNode *pCardNodeTail=*ppCardNodeHead;
if(pCardNodeHead == NULL)
{// 第一张卡,通过ppCardNodeHead将表态指针返回pCardNodeHead = pCardNode;pCardNodeTail = pCardNode;
*ppCardNodeHead = pCardNode;
}
else{pCardNodeTail = pCardNodeHead;while(pCardNodeTail->next != NULL)pCardNodeTail = pCardNodeTail->next;pCardNodeTail->next = pCardNode;
pCardNodeTail = pCardNode;}pCardNodeTail->next = NULL;saveCard(&card, CARDPATH);return SUCCESS;
}

displayCard()

void displayCard(CardNode* pCardNodeHead)
{if(pCardNodeHead == NULL){cout << endl << endl <<"一张上机卡都没有!" << endl << endl;return;}cout << "卡号\t状态\t余额\t累计使用\t使用次数\t上次使用时间" << endl;CardNode* pCur = pCardNodeHead;while(pCur != NULL){char aLastTime[TIMELENGTH] = {0};//char* aLastTime=NULL;timeToString((pCur->data).tLast, aLastTime);cout << pCur->data.aName << "\t" ;if(pCur->data.nStatus == USING)cout << "上机\t";else if(pCur->data.nStatus == UNUSE)cout << "未上机\t";else if(pCur->data.nStatus == INVALID)cout << "注销\t";elsecout << "错误\t";cout << pCur->data.fBalance << "\t";cout << pCur->data.fTotalUse << "\t\t" << pCur->data.nUseCount <<
"\t\t" << aLastTime << endl;pCur = pCur->next;}
}

cardIsExist()

Card* cardIsExist(string strNo, int &nCardIndex, CardNode* const pCardNodeHead)
{CardNode *pCardNode = pCardNodeHead;nCardIndex = 0;while(pCardNode != NULL){if(strcmp(pCardNode->data.aName,strNo.c_str())==0){return &(pCardNode->data);}pCardNode = pCardNode->next;nCardIndex++;}
return NULL;
}

service.cpp

addCard()

void addCard(CardNode** ppCardNodeHead)
{string strNo;string strPwd;float fBalance;if(inputNoPwdBalance(strNo, strPwd, fBalance)){int nResult = addNewCard(strNo, strPwd, fBalance, ppCardNodeHead);switch(nResult){case FINDCARD:{cout << endl << endl << "卡【" << strNo << "】已经存在,添加新
卡失败!" << endl << endl;break;}case SUCCESS:{cout << endl << endl << "添加新卡成功!" << endl << endl;cout << "新卡卡号:" << strNo << endl;cout << "新卡金额:" << fBalance << endl;break;}default:{cout << endl << endl << "系统错误!" << endl << endl;break;}}}else{cout << endl << endl << "输入的【卡号,密码,金额】等信息格式不符号要求,
添加卡失败!" << endl << endl;}
}
//void queryCard(vector<Card> &vec)
void queryCard(CardNode* const pCardNodeHead)
{displayCard(pCardNodeHead);
}

clearData()

由于链表节点是动态生成的,我们在退出系统时,应该删除动态生成的节点。

void clearData(CardNode* pCardNodeHead)
{CardNode *pCardNode;while(pCardNodeHead != NULL){pCardNode = pCardNodeHead;pCardNodeHead = pCardNodeHead->next;delete pCardNode;}
}

具体实现(上机下机功能)

model.h

//计费信息结构体,保留每次上机的信息
struct Billing
{char aCardName[18];//卡号time_t tStart;//上机时间time_t tEnd;//下机时间float fAmount;//消费金额int nStatus;//消费状态,0-未结算,1-已结算int nDel;//删除标识,0-未删除,1-已删除
}//计费信息结点
struct BillingNode
{Billing data;struct BillingNode *next;
}//上机信息结构体
struct LogonInfo
{char aCardName[18];//上机卡号time_t tLogon;//上机时间float fBalance;//上机时卡余额
}//下机信息结构体
struct SettleInfo
{char aCardName[18];//卡号time_t tStart;//上机时间time_t tEnd;//下机时间float fAmount;//消费金额float fBalance;//余额
}

AMS.cpp

系统启动时,首先要初始化计费记录的链表,并将链表的表头存储起来提供给其它需要使用计费记录的模块使用。BILLINGPATH 是定义计费记录文件的常量。

BillingNode* pBillingNodeHead=NULL;
pBillingNodeHead=BillingListInit(BILLINGPATH);

billList.cpp

BillListInit()

BillingNode* BillListInit(const string billingFilename)
{ifstream billingfile(billingFilename);BillingNode *pBillingNode, *pBillingNodeHead, *pBillingNodeTail;Billing billing;if(!billingfile.is_open()){return NULL;}
pBillingNodeHead = NULL;
pBillingNodeTail = NULL;while(1){billingfile.read((char*)&billing, sizeof(Billing));if(billingfile.eof()){break;}pBillingNode = new BillingNode;pBillingNode->data = billing;if(pBillingNodeHead == NULL){pBillingNodeHead = pBillingNode;pBillingNodeTail = pBillingNode;}else{pBillingNodeTail->next = pBillingNode;pBillingNodeTail = pBillingNode;}}pBillingNodeTail->next = NULL;billingfile.close();return pBillingNodeHead;
}

shangJi()

输入上机的卡号和密码,如果正确,则形成一条上机的记录,①该记录作为一个节点插入到上机记录的链表的末尾,②同时也要将这条记录添加在计费信息记录文件 billing.dat的末尾,③还要修改卡在文件和链表中的状态,即变为上机。
如果不正确,则给出具体的错误提示信息。

void shangJi(CardNode* pCardNodeHead, BillingNode **ppBillingNodeHead)
{string strNo;string strPwd;LogonInfo* pInfo = new LogonInfo; // 上机信息,用于显示char aTime[TIMELENGTH] = {0}; // 上机时间,用于显示if(inputNoPwd(strNo, strPwd)){cout << endl << "----------上机信息----------" << endl ;// 根据上机结果,提示不同信息int nResult = logon(strNo, strPwd, pInfo, pCardNodeHead,
ppBillingNodeHead);switch(nResult){case NOFINDCARD:case NOMATCH:{cout << endl << endl << "卡不存在,或卡信息不对,不能上机!" <<
endl << endl;break;}case SUCCESS:{timeToString(pInfo->tLogon, aTime);cout << endl;cout << "卡号: \t" << strNo << endl;cout << "余额: \t" << pInfo->fBalance << endl;cout << "上机时间:\t" << aTime << endl;break;}case USING:{cout << endl << "该卡正在使用,不能重复上机!" << endl;break;}case INVALID:{cout << endl << "该卡已注销,不能上机!" << endl;break;}case ENOUGHMONEY:{cout << endl << "卡余额为0,不能上机!" << endl;break;}default:{break;}}}else{cout << endl << endl << "卡号或者密码格式不正确,上机失败!" << endl <<
endl;}delete pInfo;
}

Logon()

int logon(string strNo, string strPwd, LogonInfo* pInfo, CardNode* pCardNodeHead,
BillingNode **ppBillingNodeHead)
{Billing billing; // 计费信息int nCardIndex;Card* pCard = cardIsExist(strNo, nCardIndex, pCardNodeHead);if(pCard == NULL)return NOFINDCARD; // 未找到卡if( strcmp(pCard->aPwd, strPwd.c_str())!=0)return NOMATCH; // 密码不匹配
if(pCard->nStatus == USING)
{return USING; // 卡正在上机
}if(pCard->nStatus == INVALID)
{return INVALID; // 卡已经注销
}
if(pCard->fBalance <= 0)
{return ENOUGHMONEY; // 卡的余额为0
}// 如果可以上机,更新卡信息
pCard->nStatus = USING; // 状态为正在使用
pCard->nUseCount++; // 使用次数加1
pCard->tLast = time(NULL); // 更新最后使用时间为当前时间
// 更新文件中的卡信息
updateCard(pCard, CARDPATH, nCardIndex);
// 添加消费记录
strcpy(billing.aCardName, strNo.c_str()); // 上机卡号
billing.tStart = time(NULL); // 上机时间
billing.tEnd = 0; // 下机时间
billing.nStatus = NOSETTLEMENT; // 消费状态
billing.fAmount = 0; // 消费金额
// 先将计费信息保存到文件中
saveBilling(&billing, BILLINGPATH);
// 在计费链表中增加一条计费信息
BillingNode* pBillingNode = new BillingNode;
pBillingNode->data = billing;
//BillingNode* pBillingNodeHead = *ppBillingNodeHead;
BillingNode* pBillingNodeTail= *ppBillingNodeHead;
if(*ppBillingNodeHead == NULL)
{*ppBillingNodeHead = pBillingNode;pBillingNodeTail = pBillingNode;
}
else{while(pBillingNodeTail->next != NULL)
pBillingNodeTail = pBillingNodeTail->next;pBillingNodeTail->next = pBillingNode;pBillingNodeTail = pBillingNode;}pBillingNodeTail->next = NULL;
// 组装上机信息
strcpy(pInfo->aCardName, strNo.c_str());
pInfo->fBalance = pCard->fBalance;
pInfo->tLogon = billing.tStart;
return SUCCESS;
}

updateCard()

bool updateCard(const Card* pCard, const string pPath, int nCardIndex)
{fstream ofile;ofile.open(pPath, ios_base::in | ios_base::out);ofile.seekp(sizeof(Card)*nCardIndex, ios_base::beg);ofile.write((char*)pCard, sizeof(Card));ofile.close();
return true;
}

saveBilling()

参考 saveCard()函数。

xiaJi ()

输入下机的卡号和密码,如果正确,则检测该卡的状态是否在上机?是否有上机的消费记录,检测余额是否够付费,如果一切正确,则可以下机。在下机过程种,需要修改卡的状态(包括链表和文件),还要修改上机消费的信息,即 billing 链表和文件。如果不正确,则给出具体的错误提示信息。

void xiaJi(CardNode* pCardNodeHead, BillingNode* pBillingNodeHead)
{string strNo;string strPwd;SettleInfo* pInfo = new SettleInfo; // 下机信息char aStartTime[TIMELENGTH] = {0}; // 上机时间char aEndTime[TIMELENGTH] = {0}; // 下机时间if(inputNoPwd(strNo, strPwd)){cout << "----------下机信息如下----------\n";int nResult = settle(strNo, strPwd, pInfo, pCardNodeHead,
pBillingNodeHead);switch(nResult){case NOFINDCARD:case NOMATCH:{cout << endl << endl << "卡不存在,或卡信息不对,下机失败!" <<
endl << endl;break;}case SUCCESS:{timeToString(pInfo->tStart, aStartTime);timeToString(pInfo->tEnd, aEndTime);cout << endl;cout << "卡号: \t" << strNo << endl;cout << "消费: \t" << pInfo->fAmount << endl;cout << "余额: \t" << pInfo->fBalance << endl;cout << "上机时间:\t" << aStartTime << endl;cout << "下机时间:\t" << aEndTime << endl;break;}case UNUSE:{cout << endl << endl << "该卡没有上机!" << endl << endl;break;}case ENOUGHMONEY:{cout << endl << endl << "卡余额不足,请先充值再下机!" << endl
<< endl;break;}default:{break;}}}else{cout << endl << endl << "卡号或者密码格式不正确,下机失败!" << endl <<
endl;}delete pInfo;
}

settle()

int settle(string strNo, string strPwd, SettleInfo* pInfo, CardNode* const
pCardNodeHead, BillingNode* const pBillingNodeHead)
{int nCardIndex;Card* pCard = cardIsExist(strNo, nCardIndex, pCardNodeHead);// 未找到卡if(pCard == NULL)return NOFINDCARD;// 密码不匹配if( strcmp(pCard->aPwd, strPwd.c_str())!=0)return NOMATCH;
// 判断该卡是否正在上机,只有正在上机卡才能进行下机操作
if(pCard->nStatus != USING)
return UNUSE;// 根据卡号,查询计费信息int nBillingIndex;Billing* pBilling = billingIsExist(strNo, nBillingIndex, pBillingNodeHead);// 如果查询计费信息为空,表示下机失败
if(pBilling == NULL)
{cout << "计费信息为空" << endl;
return UNUSE;
}// 计算消费金额
double dbAmount = getAmount(pBilling->tStart);// 如果余额小于消费金额,则不能进行下机
float fBalance = pCard->fBalance - (float)dbAmount;
if(fBalance < 0)
{return ENOUGHMONEY;
}
// 更新卡信息
pCard->fBalance = fBalance; // 余额
pCard->nStatus = UNUSE; // 状态
pCard->tLast = time(NULL); // 上次使用时间
// 更新文件中的卡信息
updateCard(pCard, CARDPATH, nCardIndex);
// 更新计费信息
pBilling->fAmount = (float)dbAmount; // 消费信息
pBilling->nStatus = YESSETTLEMENT; // 状态,已结算
pBilling->tEnd = time(NULL); // 下机时间
// 更新文件中的计费信息
updateBilling(pBilling, BILLINGPATH, nBillingIndex);
// 组装下机信息
strcpy(pInfo->aCardName, strNo.c_str()); // 卡号
pInfo->fAmount = (float)dbAmount; // 消费金额
pInfo->fBalance = fBalance; // 余额
pInfo->tStart = pBilling->tStart; // 上机时间
pInfo->tEnd = time(NULL); // 下机时间
return SUCCESS;
}

getAmount()

// 根据上机时间,计算消费金额
double getAmount(time_t tStart)
{double dbAmount = 0; // 消费金额
int nCount = 0; // 上机的时间单元数,每个单元15分钟
int nSec = 0; // 消费时间(单位:秒)
int nMinutes = 0; // 消费时间(单位:分钟)
time_t tEnd = time(NULL); // 结算时间为当前时间
// 计算消费时长
nSec = (int)(tEnd - tStart);
nMinutes = nSec / 60;
// 计算消费的时间单元数
if(nMinutes % UNIT == 0)
{nCount = nMinutes/UNIT;
}
else
{nCount = nMinutes/UNIT + 1;
}
if(nCount == 0)nCount = 1;
// 计算消费金额
dbAmount = nCount * CHARGE;
return dbAmount;
}

billingIsExist ()

// 判断卡的计费信息是否存在,并返回计费在链表中的节点
Billing* billingIsExist(string strNo, int& nBillingIndex, BillingNode
*pBillingNodeHead)
{BillingNode *pBillingNode = pBillingNodeHead;nBillingIndex = 0;while(pBillingNode != NULL){if(strcmp(pBillingNode->data.aCardName,strNo.c_str())==0 &&
pBillingNode->data.nStatus == NOSETTLEMENT){return &(pBillingNode->data);}pBillingNode = pBillingNode->next;nBillingIndex++;}return NULL;
}

updateBilling()

参考 saveBilling()函数。


总结

剩下的充值退费和销卡的 功能就不一一列举了,详细的源工程和实验报告请自取。
实验内容较多较杂,有不清楚的可参考以下链接。
链接:冲冲冲~
提取码:3jl8
复制这段内容后打开百度网盘手机App,操作更方便哦

武汉理工大学计算机基础与编程综合实验——网吧计费管理系统第二个版本相关推荐

  1. 武汉理工大学计算机基础与编程综合实验——网吧计费管理系统第一个版本

    文章目录 前言 系统需求分析 基本功能结构 卡管理:新增卡.查询卡.注销卡 计费标准管理:新增标准.查询标准.删除标准.修改标准. 计费管理:上机.下机. 费用管理:充值.退费. 查询统计:查询消费记 ...

  2. [计算机基础与编程综合实验]计费管理系统

    文章目录 一.快速开始 二.项目介绍 三.组织结构 四.功能架构 五.项目迭代 六.效果展示 6.1 系统界面 6.2 卡管理 6.3 计费管理 6.4 费用管理 6.5 退出系统 七.许可证 一.快 ...

  3. 武汉理工大学计算机基础与编程实验—网吧计费管理系统(含扩展超级管理员功能)

    billing_file.h #ifndef BILLING_FILE_H #define BILLING_FILE_H //避免头文件被重复包含 #include"model.h" ...

  4. 武汉理工大学计算机网,武汉理工大学计算机基础综合实验

    [实例简介] 武汉理工大学软件工程专业计算机基础综合实验(c实验),计费管理系统.基本功能加部分扩展功能实现,经过验收合格. [实例截图] [核心代码] 计算机基础综合实验 └── AMS ├── A ...

  5. 武汉理工大学-Java面向对象与多线程综合实验-(7)多线程基础

    实验目标 本实验为此系列的最后一次实验,目标在实验 (6) 的基础上增加多线程功能,使得档案系统能允许多个用户同时进行登录操作,同时实现线程之间必要的同步互斥功能. 模块解析 此次实验模块与实验 (6 ...

  6. 武汉理工大学桂林老师java_武汉理工大学-Java面向对象与多线程综合实验-(1)封装、继承与多态...

    实验目标 实现一个档案管理系统的用户管理模块的初步模型.功能包括:密码机制的登录界面:普通用户对自身信息的查询.修改:管理员用户对其他用户信息的增添.删除.修改. 模块解析 用户分为:Administ ...

  7. 计费管理系统(武汉理工大学计算机基础与综合编程实验)

    整个实验比较简单,直接展示所有代码 1.global.h #ifndef global_h #define global_h#define FALSE 0 #define TRUE 1#endif / ...

  8. 武汉理工大学计算机组成与系统结构 Educoder实验

    文章目录 前言 实验资料 一.计算机数据表示实验 第1关:汉字国标码转区位码实验 第2关:汉字机内码获取实验 第3关:偶校验编码设计 第4关:偶校验解码电路设计 第5关:16位海明编码电路设计 第6关 ...

  9. 2023武汉理工大学计算机考研信息汇总

    武汉理工大学计算机科学与技术学院 计算机学院经过20多年的发展与建设,目前已具备"计算机应用技术"博士学位授予权."计算机应用技术"和"计算机软件与理 ...

最新文章

  1. Linux下安装和使用Latexdiff
  2. (转载)Android进阶2之Activity之间数据交流(onActivityResult的用法)
  3. Xamarin Essentials教程检查网络连通性Connectivity
  4. spring boot+mybatisplus集成后访问项目接口404
  5. 类的主动使用与被动使用等
  6. 早期访问中具有NetBeans的Oracle公共云Java服务
  7. win7计算机双击空白,win7系统控制面板“打开或关闭Windows 功能”空白没有任何选项的解决方法...
  8. wifi共享大师电脑版_【小度wifi驱动下载】小度wifi驱动win10官方下载 v3.1 电脑版...
  9. 知识就是力量!(内含赠书福利)
  10. [C++]动态规划系列之币值最大化
  11. python中for循环遍历文件_Python中的用for,while循环遍历文件实例
  12. Atitit 软件开发体系法规大全v2.docx Atitit 软件开发体系大全 目录 1. 基本法(类似宪法) 1 2. 行政法 1 3. 流程法民商法 2 3.1. Ui提升法 2 3.2. 功
  13. 线性代数学习指导与MATLAB编程实践,线性代数学习指导与MATLAB编程实践(邵建峰)...
  14. FFmpeg源代码简单分析-通用-结构体分析-AVCodec
  15. App微信小程序测试流程及要点
  16. OpenCV读取图片
  17. python心得总结知识点和收获,千锋Python培训学员心得 在总结中收获提升
  18. linux桌面lxde 安装_Ubuntu怎么安装轻量级的LXDE桌面
  19. 寻找java兼职(全职)人员
  20. CSDN写漂亮博客的技巧--改字体大小颜色、插入多列表格、字体高亮等

热门文章

  1. 删除 PDF 页面的 5 大方法(最新更新)
  2. 期货交易软件哪个好?为什么选择期货MT4平台软件?
  3. IT人士最容易得的癌症
  4. Linux启动过程学习
  5. 最简单的uvm程序和vcs编译命令
  6. 【机器学习】R语言进行机器学习方法及实例
  7. MPLS隧道——单域基础理论讲解
  8. mysql 视图varchar_MySQL视图
  9. 快速从入门到精通,建议细读
  10. OpenCV小项目:图像融合(泊松融合—Possion Blending)