虽然说是三人合作,但其实基本上是我一个人写的
总的来说,这是个体力活,而且还是个没有任何结构性编程的体力活,就当是我象牙塔时代的一个见证吧
本博文面向大一大二水友。
简易银行卡管理系统
(1)开户:创建一个新的账户,接受用户输入的身份证号,以及账户密码,判断用户输入的身份证号是否唯一且账户密码是否符合要求,如验证成功则为该用户生成一个唯一的帐号。
(2)存款:在用户输入正确的帐号和密码的情况下,接受用户输入的存款金额,并对该帐号的存款信息进行更新。
(3)取款:在用户输入正确的帐号和密码的情况下,接受用户输入的取款金额。取款金额不应该大于当前帐号存款金额,当取款金额不大于当前帐号存款金额时,执行取款操作,并对该帐户的存款信息进行更新。
(4)挂失:在用户输入正确的帐号和密码的情况下,接受用户挂失操作。当帐号挂失后,与该帐号相关的操作都将被禁止。
(5)销户:在用户输入正确的帐号和密码的情况下,接受用户销户。当用户销户后,该帐号将被永久删除。
(6)转帐:在用户输入正确的帐号和密码的情况下,接受用户转账操作,转帐金额不应该大于当前帐号存款金额,当转帐金额不大于当前帐号存款金额时,执行转帐操作,并对该帐户的存款信息及转帐的接受账户的存款信息进行更新。
(7)修改账户密码:在用户输入正确的帐号和密码的情况下,接受用户修改密码操作,用户输入的原密码,若用户输入的密码与原密码匹配,则接受用户输入的新密码,若用户两个输入的密码相同,则修改账户密码,并对数据文件进行更新操作。
(8)查看余额:在用户输入正确的帐号和密码的情况下,接受用户查看余额操作,该模块只涉及数据查询,并不涉及数据文件更新操作。
(9)查看用户交易历史:在用户输入正确的帐号和密码的情况下,接受用户查看用户交易历史操作,系统将显示当前账户的最近的存、取款操作记录,该模块只涉及数据查询,并不涉及数据文件更新操作。
帐号的结构体为Node,存在List这个直接取值法构造的哈希表中,交易历史是一个链表,每个帐号里都包含一个表头。销毁帐号时,将该帐号在哈希表中的位置存在链栈中,下次开户时先从链栈中找空闲的节点。数据库是在txt中读写,比较原始(笑)
上代码
#include "stdafx.h"
#include
#include
#include
#include "iostream"
using namespace std;
typedef struct FreeNode
{
int freePos;
FreeNode *next;
};
typedef struct Log
{
char Msg[10];
double Money;
Log *next;
}Log;
typedef struct Node
{
char ID[20];
char pwd[7];
float money;
bool isGua;
Log *logHead;
bool isCancel;
}Node;
typedef struct List
{
Node list[10000];
int num = 1;
}List;
bool CheckCode(char code[])
{
int count = 0;
for (int i = 0; code[i] != '\0'; i++)
{
if (code[i] < 48 || code[i]>57)
return false;
count++;
}
if (count == 6)
return true;
else return false;
}
void CreateLogNode(List &head, int pos, char str[], float money)
{
Log *tail = head.list[pos].logHead;
while (tail->next != nullptr)
{
tail = tail->next;
}
strcpy_s(tail->Msg, str);
tail->Money = money;
Log *newTail = (Log*)malloc(sizeof(Log));
tail->next = newTail;
newTail->next = nullptr;
}
void ShowWelcomePanel()
{
cout << endl << "**********************************" << endl;
cout << "* 欢迎来到银行管理系统 *" << endl;
cout << "* 1.开 户 *" << endl;
cout << "* 2.登 陆 *" << endl;
}
void ShowOperationPanel()
{
cout << endl << "**********************************" << endl;
cout << "* 欢 迎 登 陆 *" << endl;
cout << "* 1.存 款 *" << endl;
cout << "* 2.取 款 *" << endl;
cout << "* 3.挂 失 *" << endl;
cout << "* 4.销 户 *" << endl;
cout << "* 5.转 账 *" << endl;
cout << "* 6.修 改 密 码 *" << endl;
cout << "* 7.查 看 余 额 *" << endl;
cout << "* 8.查看交易历史 *" << endl;
cout << "* 9.退出 *" << endl;
}
Node* FindAccount(int account, List &head)
{
if (account >= 10001)return nullptr;
Node *p = &(head.list[account]);
if (p->isGua == 204)
{
return nullptr;
}
return p;
}
void CreateNode(List &head, char id[], char code[])
{
strcpy_s(head.list[head.num].ID, id);
strcpy_s(head.list[head.num].pwd, code);
head.list[head.num].isGua = false;
head.list[head.num].money = 0;
head.list[head.num].isCancel = false;
head.list[head.num].logHead = (Log*)malloc(sizeof(Log));
Log* tail = (Log*)malloc(sizeof(Log));
head.list[head.num].logHead->next = tail;
tail->next = nullptr;
cout << "您的帐号为:" << head.num << endl;
head.num++;
}
bool notDuplicate(char id[20], List &head) //开户的时候检查身份证有没有重复
{
for (int i = 0; ipwd) == 0)
{
return true;
}
else return false;
}
void UpdateCode(Node *node)
{
char code[7];
if (node->isGua)
{
cout << "该卡号已挂失,无法修改" << endl;
return;
}
while (true)
{
cout << "请输入旧密码" << endl; cin >> code;
if (!strcmp(code, node->pwd))
{
cout << "请输入新密码" << endl;
cin >> code;
while (true)
{
if (CheckCode(code))
{
break;
}
else
{
cout << "密码不符合要求,请重新输入" << endl;
cin >> code;
}
}
strcpy_s(node->pwd, code);
cout << "密码修改成功" << endl;
return;
}
else
{
cout << "密码错误" << endl;
}
}
}
void ShowMoney(Node* node)
{
cout << "您的账号余额为:" << node->money << endl;
}
void ShowLog(Node *node)
{
Log *p = node->logHead;
for (p = p->next; p->next != nullptr; p = p->next)
{
cout << " " << p->Msg << p->Money << endl;
}
}
void Save(Node* node, float money, List &head)
{
node->money += money;
Log *log = (Log*)malloc(sizeof(Log));
log->Money = money;
strcpy_s(log->Msg, "存款:");
log->next = node->logHead->next;//bug
node->logHead->next = log;
}
void Take(Node* node, float money)
{
if (node->money - money < 0)
{
cout << "账户余额不足" << endl;
return;
}
node->money -= money;
Log *log = (Log*)malloc(sizeof(Log));
log->Money = money;
strcpy_s(log->Msg, "取款:");
log->next = node->logHead->next;
node->logHead->next = log;
}
void InitDataBase(List &head)
{
int i = 1;
string bufferStr;
char buffer[100];
ifstream NodesDB("D:\\Nodes.txt");
if (!NodesDB)
{
cout << "数据库不存在!" << endl;
return;
}
while (getline(NodesDB, bufferStr))
{
#pragma warning( disable : 4996)
strcpy(buffer, bufferStr.c_str());
char *bufferSplit = strtok(buffer, "|");
int pos = 1;
while (bufferSplit != nullptr)
{
if (pos == 1)strcpy(head.list[i].ID, bufferSplit);
if (pos == 2)strcpy(head.list[i].pwd, bufferSplit);
if (pos == 3)head.list[i].money = atof(bufferSplit);
if (pos == 4)head.list[i].isGua = strcmp("0", bufferSplit) == 0 ? false : true;
if (pos == 5)head.list[i].isCancel = strcmp("0", bufferSplit) == 0 ? false : true;
bufferSplit = strtok(NULL, "|");
pos++;
}
i++;
head.num = i;
//初始化历史记录
for (i = 1; i < head.num; i++)
{
head.list[i].logHead = (Log*)malloc(sizeof(Log));
Log *tail = (Log*)malloc(sizeof(Log));
head.list[i].logHead->next = tail;
tail->next = nullptr;
}
}
ifstream in("D:\\NodesDBLog.txt");
if (!in)
{
cout << "操作历史数据库不存在!";
return;
}
bool isMoney = true;
float money;
i = 1;
while (getline(in, bufferStr))
{
#pragma warning( disable : 4996)
strcpy(buffer, bufferStr.c_str());
if (strcmp(buffer, "***") == 0)
{
i++;
continue;
}
char *bufferSplit = strtok(buffer, "|");
while (bufferSplit != nullptr)
{
if (isMoney)
{
money = atof(bufferSplit);
isMoney = false;
bufferSplit = strtok(NULL, "|");
continue;
}
if (isMoney == false)
{
CreateLogNode(head, i, bufferSplit, money);
isMoney = true;
bufferSplit = strtok(NULL, "|");
continue;
}
}
}
}
void OutStreamToDB(List &head)
{
ofstream outNode("D:\\Nodes.txt");
for (int i = 1; i < head.num; i++)
{
outNode << head.list[i].ID << '|';
outNode << head.list[i].pwd << '|';
outNode << head.list[i].money << '|';
outNode << head.list[i].isGua << '|';
outNode << head.list[i].isCancel << endl;
}
ofstream outLog("D:\\NodesDBLog.txt");
Log *log;
for (int i = 1; i < head.num; i++)
{
log = head.list[i].logHead->next;
while (log->next != nullptr)
{
outLog << log->Money << '|';
outLog << log->Msg << endl;
log = log->next;
}
outLog << "***" << endl;
}
}
void GuaShi(Node* node)
{
node->isGua = true;
cout << "账号挂失成功!" << endl;
}
void DeleteNode(FreeNode &freeList, Node &node, int pos)
{
node.isCancel = true;
FreeNode *free = (FreeNode*)malloc(sizeof(FreeNode));
free->freePos = pos;
free->next = freeList.next;
freeList.next = free;
cout << "注销成功!" << endl;
}
bool CheckFree(FreeNode &freeList, List &list, char id[], char code[])
{
FreeNode *p = freeList.next;
if (p == nullptr)return false;
else
{
int i = p->freePos;
FreeNode *de = p;
freeList.next = p->next;
free(de);
strcpy_s(list.list[i].ID, id);
strcpy_s(list.list[i].pwd, code);
list.list[i].money = 0;
list.list[i].isCancel = false;
list.list[i].isGua = false;
Log *p = list.list[i].logHead->next;
Log *q;
while (p->next != nullptr)
{
q = p;
p = p->next;
free(q);
}
list.list[i].logHead->next = p;
cout << "您的账号是" << i << endl;
return true;
}
}
void Transfer(List &head, Node &me,int mypos)
{
cout << "请输入对方账号" << endl;
int it;
cin >> it;
while (true)
{
if (head.list[it].isCancel || head.list[it].isCancel == 204)
{
cout << "该账户不存在!请重新输入" << endl;
cin >> it;
}
else break;
}
cout << "请输入金额" << endl;
float money;
cin >> money;
while (true)
{
if (money > me.money)
{
cout << "金额不足,请重新输入" << endl;
cin >> money;
}
else break;
}
me.money -= money;
head.list[it].money += money;
char str1[20] = "转给";
char target1[20];
itoa(it,target1,10);
strcat(str1, target1);
strcat(str1, ":");
CreateLogNode(head, mypos, str1, money);
char str2[20] = "收到";
char target2[20];
itoa(mypos, target2, 10);
strcat(str2, target2);
strcat(str2, ":");
CreateLogNode(head, it, str2, money);
}
void main()
{
List head;
FreeNode *freeHead = (FreeNode *)malloc(sizeof(FreeNode));
freeHead->next = nullptr;
InitDataBase(head);
int state;
Node *node = nullptr;
char id[20], code[7];
int account;
while (true)
{
node = nullptr;
ShowWelcomePanel();
cin >> state;
switch (state)
{
case 1:
cout << "请输入要创建的身份证号" << endl; cin >> id;
while (true)
{
if (notDuplicate(id, head))break;
cout << "身份证重复,请重新输入" << endl; cin >> id;
}
cout << "请输入要创建的密码(6位数字)" << endl; cin >> code;
while (true)
{
if (CheckCode(code))
{
break;
}
else
{
cout << "密码不符合要求,请重新输入" << endl;
cin >> code;
}
}
if (CheckFree(*freeHead, head, id, code)) {}
else CreateNode(head, id, code);
break;
case 2:
cout << "请输入账号" << endl; cin >> account;
bool loop = true;
while (loop)
{
node = FindAccount(account, head);
if (node == nullptr)
{
cout << "您输入的账号为空,请重新输入" << endl; cin >> account;
continue;
}
while (loop)
{
cout << "请输入密码" << endl; cin >> code;
if (!CodeLogin(node, code))
{
cout << "密码错误" << endl; continue;
}
loop = false;
}
}
if (node->isCancel)
{
cout << "该账号不存在!" << endl;
break;
}
if (node->isGua)
{
cout << "该账号已挂失!" << endl;
break;
}
ShowOperationPanel();
float money;
bool stop = false;
while (true)
{
cin >> state;
if (state == 9)
break;
switch (state)
{
case 1:cout << "请输入存款金额:" << endl;
cin >> money;
Save(node, money, head);
cout << "存款成功!" << endl;
break;
case 2:cout << "请输入取款多少" << endl;
cin >> money;
Take(node, money);
cout << "取款成功!" << endl;
break;
case 3:GuaShi(node); stop = true;
break;
case 4:DeleteNode(*freeHead, *node, account); stop = true;
break;
case 5:Transfer(head, *node,account); cout << "转账成功!" << endl;
break;
case 6:UpdateCode(node); cout << "更改成功!" << endl;
break;
case 7:ShowMoney(node); cout << "显示完毕!" << endl;
break;
case 8:ShowLog(node); cout << "显示完毕!" << endl;
break;
}
if (stop)break;
}
}
OutStreamToDB(head);
}
}
其一:本程序的设计思想是面向过程,完全抛弃了先进的OOP和ECS的设计思想,子函数杂乱无章,函数之间具有非常高的耦合度,牵一发而动全身,给后期的迭代和重构造成了巨大的困难;其二:交易记录中缺少时间的显示。其三,缺少多线程优化,在处理大量数据信息的时候程序一定会出现响应度很慢的情况,个人认为可以将对数据库的操作封装到一个进程中,或者通过改进哈希函数,通过用户输入的帐号优先从内存中加载这个数据,或者完全抛弃内存,只从数据库中读取一个帐号信息再输出出去。其四,数据库输出的效率低下,每次修改数据保存时,都是将内存中的哈希表中的全部数据全部覆盖地输出到数据库中,做了大量的无用功。其五:自己造的轮子太多,很少用到c++的标准模版库。
(捂脸)