✅更多源码 | 课设
✅ 🚀快速解决各种课设毕设,窗体、网站、管理系统,范围 (Java、C#、C/C++、数据库、Vue、小程序)
✅ 🚀 文末联系 源码 / 定做🚀
--------------文档末可加q
模拟银行的自动取款机使用过程中的界面和用户交互过程。实现查询银行卡余额、取款、修改密码、退出系统等功能。
功能要求:
(1)卡号、密码输入最多三次,否则直接退出系统。
(2)取款功能:取款金额受卡余额、机单笔最大取款金额及机当前剩余金额的限制。
(3)查询功能:实现查询余额功能。
(4)更改密码:实现密码更改功能,对于密码要有2次验证。
(5)锁卡功能:实现卡被锁的功能。
(6)退卡功能:实现退出系统功能。
目录
1 基本功能描述 1
2 设计思路 1
3 软件设计 4
3.1 设计步骤 4
3.2 界面设计 5
3.3 关键功能的实现 11
4 结论与心得体会 12
5 参考文献 13
6 附录 13
6.1 调试报告 13
6.2 测试结果 14
6.3 关键源代码 15
简单计算器
1 基本功能描述
(1)卡号、密码输入最多三次,否则直接退出系统。
(2)取款功能:取款金额受卡余额、机单笔最大取款金额及机当前剩余金额的限制。
(3)查询功能:实现查询余额功能。
(4)更改密码:实现密码更改功能,对于密码要有2次验证。
(5)锁卡功能:实现卡被锁的功能。
(6)退卡功能:实现退出系统功能。
2 设计思路
本系统模拟了ATM机的存取款管理功能,主要包括用户登录、取款、查询余额、修改密码、锁卡和退卡等功能。系统通过类的方式对管理员、银行用户和取款记录进行管理,并使用文件存储数据,确保数据的持久化。
用户登录与验证:
用户登录时,系统会要求输入用户名和密码。如果输入错误超过三次,账户将被锁定,用户需要联系管理员解锁。
登录成功后,系统会根据用户类型(管理员或普通用户)显示不同的功能菜单。
取款功能:
用户可以选择取款功能,系统会检查用户的账户余额和取款金额。如果余额不足或取款金额超过单笔最大限额,系统会提示取款失败。
取款成功后,系统会更新用户的账户余额,并记录取款操作。
查询余额:
用户可以随时查询自己的账户余额,系统会显示当前账户的余额信息。
修改密码:
用户可以选择修改密码功能,系统会要求输入旧密码进行验证。验证通过后,用户可以设置新密码,系统会更新用户的密码信息。
锁卡功能:
如果用户连续三次输入错误的密码,系统会自动锁定该账户,用户需要联系管理员解锁。
退卡功能:
用户可以选择退出系统,系统会保存当前的操作记录并退出。
详细设计
用户登录:
用户输入用户名和密码,系统通过Bank::getOne方法查找用户信息并进行验证。
如果验证失败,系统会提示重新输入,超过三次则锁定账户。
取款功能:
用户输入取款金额,系统通过Quk::add方法检查余额并更新账户信息。
如果余额不足,系统会提示取款失败。
查询余额:
用户选择查询功能,系统通过Bank::find方法显示当前账户余额。
修改密码:
用户选择修改密码功能,系统通过Bank::modInfo方法验证旧密码并设置新密码。
锁卡功能:
如果用户连续三次输入错误密码,系统会调用Bank::write保存账户状态锁定账户。
退卡功能:
用户选择退卡功能,系统保存当前操作记录并退出程序。
本系统通过类的方式对用户和取款记录进行管理,使用文件存储数据,确保数据的持久化。系统功能完善,能够满足ATM机的基本操作需求,并且具有良好的用户交互体验。
3 软件设计
3.1 登录功能
开始:用户进入登录界面。
选择登录类型:用户选择是管理员登录还是普通用户登录。
管理员登录:
用户输入管理员的用户名和密码。
系统验证用户名和密码是否正确。
如果验证成功,进入管理员菜单。
如果验证失败,检查是否超过三次错误输入。如果超过三次,提示登录失败并返回主菜单;否则,重新输入用户名和密码。
普通用户登录:
用户输入普通用户的用户名和密码。
系统验证用户名和密码是否正确。
如果验证成功,进入普通用户菜单。
如果验证失败,检查是否超过三次错误输入。如果超过三次,锁定账户并提示联系管理员;否则,重新输入用户名和密码。
管理员功能操作:登录成功后,管理员可以进行相关操作。
普通用户功能操作:登录成功后,普通用户可以进行相关操作。
返回主菜单:登录失败或账户锁定后,返回主菜单。
3.2 取款流程
流程图说明
开始:用户进入取款功能。
用户登录:用户必须先登录系统,登录成功后才能进行取款操作。如果登录失败,返回主菜单。
输入取款金额:用户输入想要取款的金额。
检查余额是否足够:
系统检查用户的账户余额是否足够支付取款金额。
如果余额不足,提示用户余额不足,取款失败,并返回取款菜单。
检查取款金额是否超过单笔限额:
如果余额足够,系统检查取款金额是否超过单笔取款限额。
如果超过限额,提示用户超过单笔限额,取款失败,并返回取款菜单。
更新账户余额:
如果余额足够且未超过限额,系统从用户账户中扣除取款金额,更新账户余额。
记录取款操作:系统记录本次取款操作,保存到取款记录中。
提示取款成功:系统提示用户取款成功。
是否继续取款:
系统询问用户是否继续取款。
如果用户选择继续取款,返回输入取款金额步骤。
如果用户选择不继续取款,返回主菜单。
3.3 管理员管理账户状态
管理员修改账户信息功能是系统中重要的管理功能之一。通过该功能,管理员可以灵活地调整银行用户的账户余额和状态,确保系统的正常运行。该功能结合了用户输入验证、数据更新和文件存储,具有良好的安全性和实用性。管理员可以修改银行用户(Bank类)的账户信息。该功能允许管理员对用户的账户余额、状态等信息进行修改。以下是该功能的详细描述,结合代码进行说明。
功能流程
管理员登录:
管理员必须先登录系统,登录成功后进入管理员菜单。
登录逻辑在login()函数中实现,管理员输入用户名和密码后,系统通过Admin::dataList进行验证。
选择修改功能:
管理员在菜单中选择“修改银行用户”功能(对应菜单选项3)。
该功能调用Bank::mod()方法。
选择要修改的用户:
系统显示所有银行用户的列表,管理员输入要修改的用户的序号。
如果输入的序号有效,系统会加载该用户的信息。
修改用户信息:
管理员可以修改用户的账户余额和状态。
修改完成后,系统会更新用户信息并保存到文件中。
代码分析
- 修改功能的入口
在管理员菜单中,选择“修改银行用户”功能会调用Bank::mod()方法。以下是相关代码:
case 3 : // 修改银行用户
Bank::find(1); // 查找银行用户
Bank::mod(); // 修改银行用户
break;
修改账户信息代码:
void Bank::mod() {
cout << “请输入您要修改的银行用户 序号(输入-1退出):”;
char c;
cin >> c;
int indexOfMod = c - ‘0’; // 将输入的字符转换为序号
if (indexOfMod >= 0 && indexOfMod < dataSize) { // 检查序号是否有效
// 开始修改
Bank *temp = dataList[indexOfMod]; // 获取要修改的用户对象
cout << "请输入账户余额:";
double yue;
cin >> yue; // 输入新的账户余额
cout << "请输入状态:";
char zhuangt[15];
cin >> zhuangt; // 输入新的状态
// 更新用户信息
temp->yue = yue; // 修改账户余额
strcpy(temp->zhuangt, zhuangt); // 修改状态
cout << "修改成功!\n";
write(); // 将修改后的数据写入文件
} else {
cout << "输入错误!\n";
}
}
修改用户信息后,系统会调用Bank::write()方法将更新后的数据保存到文件中。以下是Bank::write()方法的代码:
void Bank::write() {
FILE *fp = NULL;
fp = fopen(“Bank.txt”, “w+”); // 打开文件
// 写入数据
for (int i = 0; i < dataSize; i++) {
Bank *t = dataList[i];
fprintf(fp, “%s %lf %s %s %s\n”, t->name, t->yue, t->zhuangt, t->username, t->password);
}
if (fp) fclose(fp); // 关闭文件
}
功能特点
权限控制:
只有管理员可以修改银行用户的信息,普通用户无法访问此功能。
管理员必须先登录系统,确保操作的安全性。
数据持久化:
修改后的用户信息会立即保存到文件(Bank.txt)中,确保数据的持久化。
用户友好:
系统会显示所有银行用户的列表,管理员可以通过序号选择要修改的用户。
修改完成后,系统会提示“修改成功”,并返回管理员菜单。
灵活性:
管理员可以修改用户的账户余额和状态,满足不同场景下的需求。
4 结论与心得体会
通过本次“模拟ATM机存取款管理系统”的设计与实现,我对C++编程中的类、数组、文件操作以及业务逻辑的实现有了更深入的理解和掌握。以下是我在项目开发中的一些心得体会和收获。
- 类的设计与封装
在本次项目中,我使用了面向对象的思想,将系统功能划分为多个类,如Admin
(管理员)、Bank
(银行用户)和Quk
(取款记录)。每个类都封装了相关的属性和方法,例如Admin
类封装了管理员的用户名和密码,Bank
类封装了银行用户的账户信息,Quk
类封装了取款记录。通过类的封装,代码结构更加清晰,功能模块化,便于维护和扩展。
在类的设计中,我还使用了静态成员变量和静态成员函数,例如dataList
和dataSize
用于存储和管理所有对象。这种设计使得数据的共享和操作更加方便,同时也减少了全局变量的使用,提高了代码的可读性和安全性。
- 数组的使用
在项目中,我使用数组来存储和管理多个对象,例如Admin::dataList
和Bank::dataList
分别用于存储管理员和银行用户的对象。通过数组,我可以方便地遍历、查找、添加和删除对象。例如,在删除功能中,我通过数组的下标操作实现了元素的删除和数组的更新。
数组的使用让我更加熟悉了C++中数组的操作,尤其是在动态管理对象时,如何通过数组的下标和循环来实现增删改查等功能。同时,我也意识到数组的局限性,例如固定大小和动态扩展的问题,这为我后续学习更高级的数据结构(如vector
)打下了基础。
- 文件操作
文件操作是本次项目中的一个重要部分。通过文件操作,我实现了数据的持久化存储。例如,Admin::read()
和Admin::write()
方法分别用于从文件中读取管理员数据和将数据写入文件。类似的功能也在Bank
和Quk
类中实现。
在文件操作中,我使用了C语言的标准库函数fopen
、fscanf
和fprintf
等。通过这些函数,我学会了如何将对象的数据保存到文件中,并在程序启动时从文件中读取数据。文件操作不仅让我掌握了C++中文件读写的基本方法,还让我理解了数据持久化的重要性。
- 业务逻辑的实现
在项目中,我实现了多个业务逻辑,例如用户登录、取款、修改密码、查询余额等。每个功能都有其独特的逻辑流程。例如,在用户登录功能中,我实现了密码错误次数的限制和账户锁定的功能;在取款功能中,我实现了余额检查和取款金额限制的逻辑。
通过这些业务逻辑的实现,我学会了如何将实际问题转化为代码逻辑,并通过条件判断、循环等控制结构来实现功能。同时,我也意识到代码的健壮性和用户体验的重要性,例如在用户输入错误时,系统会给出明确的提示,并引导用户重新输入。
- 心得体会
通过本次项目,我深刻体会到编程不仅仅是写代码,更是一个不断思考和优化的过程。在开发过程中,我遇到了很多问题,例如数组越界、文件读写错误等,但通过调试和查阅资料,我逐渐解决了这些问题。这让我更加理解了调试和测试的重要性。
此外,我还学会了如何将一个大问题分解为多个小问题,并逐步解决。例如,我将系统功能划分为登录、取款、查询等多个模块,每个模块都独立实现,最后再将它们整合在一起。这种模块化的设计思想让我在开发过程中更加有条理。
总的来说,本次项目让我在C++编程的多个方面都有了显著的进步,尤其是在类、数组、文件操作和业务逻辑的实现上。我相信这些经验和技能将为我今后的编程学习和项目开发打下坚实的基础。
5 参考文献
[1] 揣锦华.面向对象程序设计与VC++实践.西安电子科技大学出版社,2005
[2] 张建宏,汤练兵,马德骏.计算机程序设计基础-C语言程序设计.科学出版社,2006
[3] 陈清华.Visual C++课程设计案例精选与编程指导.东南大学出版社,2004
6.3 关键源代码
class Admin { //定义 管理员 类
public:
char username[15] ; // 用户名
char password[15] ; // 密码
static Admin* dataList[100];
static int dataSize;
static void read();//读文件
static void write();//写文件
static void add();//添加
static void del();//删除
static int delByIndex(int index);//根据下标删除
static void mod();//修改
static void find(int all);//查找
static void sort(int select);//排序
static Admin* getOne(string name, string s);//存在判断函数
static void modInfo();
};
Admin* Admin::dataList[100];//必须类外初始化,用于存储管理员
int Admin::dataSize = 0; // 初始化数据大小
class Bank { //定义 银行用户 类
public:
char name[15] ; // 开户名
double yue ; // 账户余额
char zhuangt[15] ; // 状态
char username[15] ; // 用户名
char password[15] ; // 密码
static Bank* dataList[100];
static int dataSize;
static void read();//读文件
static void write();//写文件
static void add();//添加
static void del();//删除
static int delByIndex(int index);//根据下标删除
static void mod();//修改
static void find(int all);//查找
static void sort(int select);//排序
static Bank* getOne(string name, string s);//存在判断函数
static void modInfo();
};
Bank* Bank::dataList[100];//必须类外初始化,用于存储银行用户
int Bank::dataSize = 0; // 初始化数据大小
class Quk { //定义 取款 类
public:
char numb[20] ; // 银行用户
double jine ; // 取款金额
static Quk* dataList[100];
static int dataSize;
static void read();//读文件
static void write();//写文件
static void add();//添加
static void del();//删除
static int delByIndex(int index);//根据下标删除
static void mod();//修改
static void find(int all);//查找
static void sort(int select);//排序
static Quk* getOne(string name, string s);//存在判断函数
};
Quk* Quk::dataList[100];//必须类外初始化,用于存储取款
int Quk::dataSize = 0; // 初始化数据大小
//定义菜单
void login();
void regist();
Admin *loginAdmin = NULL;
void menuAdmin ();
Bank *loginBank = NULL;
void menuBank ();
int loginStatus = 0;//意义 如:0 未登录 1 管理员 2 用户
// 主函数
int main() {
//读取数据
Admin::read ();//读取管理员
Bank::read ();//读取银行用户
Quk::read ();//读取取款
while(1) {
cout<<“---------------------------------------------\n*------------1:登陆\n*------------2:注册\n*---------------------------------------------*\n请输入选择:”;
int logout=0; //返回上一级标志
int select =0;
cin>>select;
if(select!=2) {
login();
} else {
regist();
}
int choice;
if(loginStatus == 1)
while(logout0) {
menuAdmin ();
cin>>choice;
switch(choice) {
case 1 :
Bank::add ();//添加银行用户
break;
case 2 :
Bank::find (1);//查找银行用户
Bank::del ();//删除银行用户
break;
case 3 :
Bank::find (1);//查找银行用户
Bank::mod ();//修改银行用户
break;
case 4 :
Bank::find (0);//查找银行用户
break;
case 5 :
Bank::sort (0);//排序银行用户
break;
case 6 :
Quk::find (0);//查找取款
break;
case 7 :
Quk::sort (0);//排序取款
break;
case 0:
cout<<“\n\n\n\t\t\t感谢使用\n\n\n”;
exit(0);
case -1:
cout<<“\n”;
logout =1;
loginStatus = 0;
break;
case -2:
Admin::modInfo();//修改个人信息
break;
default :
getchar();
cout<<“\n\n\n\t提示:没有这个选项!请重新输入!\n\n\n\n”;
system(“pause”);
break;
}
}
if(loginStatus == 2)
while(logout0) {
menuBank ();
cin>>choice;
switch(choice) {
case 1 :
Quk::add ();//添加取款
break;
case 2 :
Quk::find (0);//查找取款
break;
case 3 :
Quk::sort (0);//排序取款
break;
case 0:
cout<<“\n\n\n\t\t\t感谢使用\n\n\n”;
exit(0);
case -1:
cout<<“\n”;
logout =1;
loginStatus = 0;
break;
case -2:
Bank::modInfo();//修改个人信息
break;
default :
getchar();
cout<<“\n\n\n\t提示:没有这个选项!请重新输入!\n\n\n\n”;
system(“pause”);
break;
}
}
}
return 0;
}
void login() {
int i;
while(loginStatus==0) {
cout << “请选择登录类型: 1. 用户 2. 管理员” << endl;
int choice;
cin >> choice;
cin.ignore(); // 消耗换行符
if (choice == 2) {
char username[20],password[20];
cout<<"请输入账号:";
cin>>username;
cout<<"请输入密码:";
cin>>password;
// 管理员 登录
Admin *admin = new Admin;
for(int i = 0 ; i < Admin::dataSize; i++) {
if(strcmp(username,Admin::dataList[i]->username)==0) {
if(strcmp(password,Admin::dataList[i]->password)==0) {
loginAdmin = Admin::dataList[i];
loginStatus = 1;
break;
}
}
}
}else{
char username[20],password[20];
Bank* bank = NULL;
cout<<"请输入账号:";
cin>>username;
bank = Bank::getOne("username",username);
while(bank == NULL){
cout<<"请输入正确账号:";
cin>>username;
bank = Bank::getOne("username",username);
}
int error = 0;
while(error<3){
cout<<"请输入密码:";
cin>>password;
if(strcmp(password,bank->password) == 0){
if(strcmp(bank->zhuangt,"锁定")==0){
cout<<"账号已经锁定!\n";
break;
}
loginBank = bank;
loginStatus = 2;
break;
}else{
error++;
cout<<"密码错误,还有"<<3-error<<"次机会!\n";
}
}
if(error == 3){
cout<<"\n\n\n\t\t\t账号锁定,请联系管理员解冻\n\n\n";
strcpy(bank->zhuangt,"锁定");
Bank::write();
break;
}
}
//判断登录情况
if(loginStatus == 0) {
cout<<"\n用户名密码错误请重新登录!\n\n";
cout<<"1.重新登录\n2.返回\n请选择:";
cin>>i;
if(i==2) {
break;
}
} else {
cout<<"\n登录成功!\n\n";
}
}
}
void regist() {
int flag = 0;//注册状态 0 失败 ,1 成功
while(flag ==0) {
cout<<“---------------------------------------------\n*------------0:返回 \n”;
cout<<“------------1:注册管理员 \n";
cout<<"------------2:注册银行用户 \n”;
cout<<“---------------------------------------------\n请输入选择:”;
int select = 0;
cin>>select;
if(select == 0) {
flag = 1;//返回
} else {
char username[20],password[20];
cout<<“请输入账号:”;
cin>>username;
;
cout<<“请输入密码:”;
cin>>password;
if( select == 1 ) {
if( Admin::getOne (“username”,username)!=NULL) { //根据用户名查找
cout<<“\n用户名已存在!\n\n”;
} else {
Admin *temp = new Admin;
strcpy( temp->username,username);
strcpy( temp->password,password);
loginAdmin = temp;
Admin::dataList[Admin::dataSize++]=temp;
loginStatus = 1;
Admin::write ();
flag = 1;
}
}
if( select == 2 ) {
if( Bank::getOne ("username",username)!=NULL) { //根据用户名查找
cout<<"\n用户名已存在!\n\n";
} else {
Bank *temp = new Bank;
strcpy( temp->username,username);
strcpy( temp->password,password);
cout<<"请输入开户名 :";
cin>>temp->name ;
temp->yue = 0.0;
strcpy(temp->zhuangt,"正常");
loginBank = temp;
Bank::dataList[Bank::dataSize++]=temp;
loginStatus = 2;
Bank::write ();
flag = 1;
}
}
if(flag == 1)
cout<<"注册成功\n\n";
else
cout<<"注册失败!\n\n";
}
}
}
void Admin::modInfo() {
cout << “\n您的个人信息如下\n”;
cout << “用户名:” << loginAdmin ->username << endl;
cout << “密码:” << loginAdmin ->password << endl;
cout << “==========================\n1,修改个人信息\n2,返回上一级\n请选择:”;
char n;
cin >> n;
if (n == ‘1’) {
cout << “请输入密码:”;
cin>>loginAdmin ->password;
for (int i = 0; i < Admin::dataSize; i++) {
if (strcmp(Admin::dataList[i]->username, loginAdmin ->username) == 0) {
Admin::dataList[i] = loginAdmin;
break;
}
}
Admin::write();
cout << “修改成功!\n”;
}
}
//是否存在判断
Admin* Admin::getOne(string name, string s) {
for (int i = 0; i < dataSize; i++) {
if( strcmp(name.c_str(),“username”)==0 && strcmp(s.c_str(), dataList[i]->username )==0) {
return dataList[i];
}
}
return NULL;
}
//读取文件内的管理员
void Admin::read() {
FILE *fp = NULL;
if (NULL == (fp = fopen(“Admin.txt”, “r”))) { //读打开
//文件不存在,不读取
return;
}
//从文件读取数据
dataSize = 0;
while (1) { //读取
//新建管理员对象
Admin *t = new Admin;
//读取数据到p