目录

前言

一,需求定义

二,具体框架

1,Manager(管理员).h头文件和BankCard(银行卡).h头文件

(1)Manager.h

(2)BankCard.h

2,文件框架

三,函数封装

1,Manager.cpp

(1) 初始化数组

(2)登录管理员

(3)注册管理员

(4)销毁释放

2,BankCard.cpp

(1)初始化银行卡

(2)初始化该银行卡对应记录

(3)初始化卡内容

(4)登录

(5)记录流水记录

(6)注册

(7)存款

(8)取款

(9)转账

(10)查余额

(11)查开户日期

(12)查流水明细

(13)挂失卡

(14)注销卡

(15)结束时销毁数组

四,函数调用

1,前置工作

2,atm_op.cpp(引用头文件后的所有函数调用)

(1)从文件中读取管理员身份信息

(2)从文件中读取银行卡身份信息

(3)将Manager数据保存到文件中

(4)将BankCard数据保存到文件中

(5)判断是否是管理员

(6)判断是否是用户

(7)银行卡解锁

(8)管理员选项界面

(9)用户选项界面

(10)管理员功能选择实现

(11)用户功能选择实现

(12)打开atm机窗口

3,main主函数

五,心得总结


前言

熟练使用c语言所练习时写的,也是大学时c语言的课设题目,但是当时老师要求用链表写,那一版的要对数据结构里链表有足够的熟练才行。

我这版的是用数组结构体写的(数组的话对于代码本身实现很简单)。

一,需求定义

首先我们需要有一个管理员和用户的不同的操作模块,两者各自有各自的登录和实现功能。

                     

其次,我是用EasyX图形库调用窗口并贴以ATM机做背景图片以实现的,用鼠标点击来确认用户或管理员所需要实现的功能模块,图放这了。

二,具体框架

1,Manager(管理员).h头文件和BankCard(银行卡).h头文件

(1)Manager.h

宏定义INITSIZE和GROWSIZE分别是初始化管理员数组初始个数和扩容倍数。

#pragma once
#define INITSIZE 10
#define GROWSIZE 2
typedef struct Manager {
	int m_id;//管理员账户id
	int m_passwd;//账号密码
}Manager;
typedef struct Array_Manager {
	Manager* managers;//管理员
	int manager_length;//当前数组总容量
	int manager_size;//记录当前数组中有效数据个数
}Array_Manager;
//初始化数组
void InitManagers(Array_Manager* parr);
//登录管理员
bool LoginManager(Array_Manager* parr, int m_id, int m_passwd);
//注册管理员
bool RegisterManager(Array_Manager* parr, int m_id, int m_passwd);
//银行卡解锁
bool FindCard(Array_Manager* parr, int m_id, int m_passwd);
//销毁释放
void DestoryManagers(Array_Manager* parr);

(2)BankCard.h

宏定义RECORDSIZE:初始化流水记录个数

宏定义INITCARDSIZE:初始化银行卡个数

宏定义GROWCARDSIZE:银行卡扩容倍数

#pragma once
#define RECORDSIZE 100
#define INITCARDSIZE 10
#define GROWCARDSIZE 2
typedef struct User {
	char name[128];//姓名
	char idcard[128];//身份证号
	long long phone;//电话号码
}User;
typedef struct Record {
	const char* time;//日期
	const char* type;//业务
	double money;//金额
}Record;
typedef struct BankCard {
	int card_id;//卡号
	int card_passwd;//卡密
	double money;//余额
	int islocked;//是否被锁
	int islost;//是否丢失
	char create_card_date[20];//开户日期
	User user;//卡主
	Record* records;//流水记录
	int records_size;//记录当前数组中有效数据个数
	int records_length;//当前数组总容量
}BankCard;
typedef struct Array_BankCard {
	BankCard* cards;//银行卡
	int cards_length;//当前数组总容量
	int cards_size;//记录当前数组中有效数据个数
}Array_BankCard;
//初始化银行卡 
void InitCardArray(Array_BankCard* parr);
//初始化该银行卡对应记录
void InitRecords(BankCard* pcard);
//初始化卡内容
void InitCard(BankCard* pcard, int id, int passwd, double money, User* puser);
//登录
int LoginCard(Array_BankCard* parr, int id, int passwd);//返回银行卡存储下标
//注册
bool RegisterCard(Array_BankCard* parr, int id, int passwd, double money, User* puser);
//存款
bool SaveMoney(Array_BankCard* parr, int index, double money);
//取款
bool Withdraw(Array_BankCard* parr, int index, double money);
//转账
bool Transfer(Array_BankCard* parr, int index, int userid, double money);
//查余额
void GetMoney(Array_BankCard* parr, int index);
//查开户日期
char* GetCretCarDate(Array_BankCard* parr, int index);
//查流水明细
void GetWaterMessage(Array_BankCard* parr, int index);
//挂失卡
bool Lost(Array_BankCard* parr, int index);
//注销卡
bool DeleteCard(Array_BankCard* parr, const char* idcard);
//结束销毁数组
void Destroy(Array_BankCard* parr);

2,文件框架

三,函数封装

1,Manager.cpp

(1) 初始化数组

用指针传递管理员数组,malloc扩容。

assert是断言函数,防止未接收到参数。

//初始化数组
void InitManagers(Array_Manager* parr) {
	assert(parr != nullptr);
	parr->managers = (Manager*)malloc(INITSIZE * sizeof(Manager));
	assert(parr->managers != nullptr);
	//memset(parr->managers, 0, INITSIZE * sizeof(Manager));//初始化堆内存
	parr->manager_length = INITSIZE;//容量初始化
	parr->manager_size = 0;//有效个数0
}

(2)登录管理员

//登录管理员
bool LoginManager(Array_Manager* parr, int m_id, int m_passwd) {
	assert(parr != nullptr);
	bool flag = false;
	for (int i = 0; i < parr->manager_size; i++) {
		if (parr->managers[i].m_id == m_id && parr->managers[i].m_passwd == m_passwd) {
			flag = true;
			break;
		}
	}
	return flag;
}

(3)注册管理员

注册时需注意是否需要扩容。

//注册管理员
bool RegisterManager(Array_Manager* parr, int m_id, int m_passwd) {
	assert(parr != nullptr);
	if (parr->manager_size == parr->manager_length) {
		Manager* temp = (Manager*)realloc(parr->managers, GROWSIZE * parr->manager_length * sizeof(Manager));
		if (temp == nullptr) {
			return false;
		}
		parr->managers = temp;
		parr->manager_length *= GROWSIZE;
	}
	Manager manager = { m_id, m_passwd };
	parr->managers[parr->manager_size++] = manager;
	return true;
}

(4)销毁释放

//销毁释放
void DestoryManagers(Array_Manager* parr) {
	assert(parr != nullptr);
	free(parr->managers);
	parr->managers = nullptr;//防止野指针
}

2,BankCard.cpp

(1)初始化银行卡

//初始化银行卡 
void InitCardArray(Array_BankCard* parr) {
	assert(parr != nullptr);
	parr->cards = (BankCard*)malloc(INITCARDSIZE * sizeof(BankCard));
	assert(parr->cards != nullptr);
	parr->cards_length = INITCARDSIZE;//容量初始化
	parr->cards_size = 0;//有效个数0
}

(2)初始化该银行卡对应记录

//初始化该银行卡对应记录
void InitRecords(BankCard* pcard) {
	assert(pcard != nullptr);
	pcard->records = (Record*)malloc(RECORDSIZE * sizeof(Record));
	assert(pcard->records != nullptr);
	pcard->records_length = RECORDSIZE;//容量初始化
	pcard->records_size = 0;//有效个数0
}

(3)初始化卡内容

这里用到time有关函数,这个是用来直接获得当前系统所用时间的,因为要写开户日期是需要直接读取到本地系统时间的。

//初始化卡内容
void InitCard(BankCard* pcard, int id, int passwd, double money, User* puser) {
	*pcard = { id, passwd, money, false, false };
	char timestr[20] = { 0 };//2023-2-18 15:00
	struct tm* p;
	time_t t;
	time(&t);//获取当前时间
	p = localtime(&t);//时间数据换算为年月日格式
	sprintf(timestr, "%d-%d-%d%d:%d", p->tm_year, p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min);
	strcpy(pcard->create_card_date, timestr);
	pcard->user = *puser;
	InitRecords(pcard);//上述初始化卡
}

(4)登录

登录这里返回银行卡存储下标位置是方便下面进行其他功能时直接操作当前账号卡。

//登录
int LoginCard(Array_BankCard* parr, int id, int passwd) {//返回银行卡存储下标
	assert(parr != nullptr);
	int index = -1;
	for (int i = 0; i < parr->cards_size; i++) {
		if (parr->cards[i].card_id == id && parr->cards[i].card_passwd == passwd && parr->cards[i].islocked == false && parr->cards[i].islost == false) {
			index = i;
			break;
		}
	}
	return index;
}

(5)记录流水记录

//记录流水记录
void InsertRecords(BankCard* pcard, const char* type, double money) {
	char timestr[20] = { 0 };//2023-2-18 15:00
	struct tm* p;
	time_t t;
	time(&t);//获取当前时间
	p = localtime(&t);//时间数据换算为年月日格式
	sprintf(timestr, "%d-%d-%d %d:%d", p->tm_year, p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min);
	Record record = { timestr, type, money };
	pcard->records[pcard->records_size++] = record;
}

(6)注册

//注册
bool RegisterCard(Array_BankCard* parr, int id, int passwd, double money, User* puser) {
	assert(parr != nullptr);
	for (int i = 0; i < parr->cards_size; i++) {
		if (strcmp(parr->cards[i].user.idcard, puser->idcard) == 0) {
			return false;
		}
	}
	BankCard bankcard;
	InitCard(&bankcard, id, passwd, money, puser);
	if (parr->cards_size == parr->cards_length) {
		BankCard* temp = (BankCard*)realloc(parr->cards, GROWCARDSIZE * parr->cards_length * sizeof(BankCard));
		if (temp == nullptr) {
			return false;
		}
		parr->cards = temp;
		parr->cards_length *= GROWCARDSIZE;
	}
	InsertRecords(&bankcard, "开户", money);//记录流水记录
	parr->cards[parr->cards_size++] = bankcard;
	return true;
}

(7)存款

//存款
bool SaveMoney(Array_BankCard* parr, int index, double money) {
	assert(parr != nullptr);
	parr->cards[index].money += money;
	InsertRecords(&parr->cards[index], "存款", money);//记录流水记录
	return true;
}

(8)取款

//取款
bool Withdraw(Array_BankCard* parr, int index, double money) {
	assert(parr != nullptr);
	bool t = parr->cards[index].money < money ? false : true;
	if (t) {
		parr->cards[index].money -= money;
		InsertRecords(&parr->cards[index], "取款", money);//记录流水记录
	}
	return t;
}

(9)转账

找不到对方或者是余额不足是不能转出去的哦。

//转账
bool Transfer(Array_BankCard* parr, int index, int userid, double money) {
	assert(parr != nullptr);
	bool t = false;
	int i = 0;
	for (; i < parr->cards_size; i++) {
		if (parr->cards[i].card_id == userid) {
			break;
		}
	}
	if (i != parr->cards_size) {
		if (parr->cards[index].money > money) {
			parr->cards[i].money += money;
			parr->cards[index].money -= money;
			InsertRecords(&parr->cards[index], "转出", -1 * money);//记录流水记录
			InsertRecords(&parr->cards[i], "转入", money);//记录流水记录
			t = true;
		}
	}
	return t;
}

(10)查余额

void GetMoney(Array_BankCard* parr, int index) {
	assert(parr != nullptr);
	printf("%lf\n", parr->cards[index].money);
}

(11)查开户日期

//查开户日期
char* GetCretCarDate(Array_BankCard* parr, int index) {
	assert(parr != nullptr);
	return &parr->cards[index].create_card_date[0];
}

(12)查流水明细

//查流水明细
void GetWaterMessage(Array_BankCard* parr, int index) {
	assert(parr != nullptr);
	for (int i = 0; i < parr->cards[index].records_size; i++) {
		printf("%s %s, %lf\n", parr->cards[index].records->time, parr->cards[index].records->type, parr->cards[index].records->money);
	}
}

(13)挂失卡

//挂失卡
bool Lost(Array_BankCard* parr, int index) {
	assert(parr != nullptr);
	parr->cards[index].islocked = 1;
	parr->cards[index].islost = 1;
	return true;
}

(14)注销卡

这个注销卡我是只给了管理员这个权限的(前后文都有提及)。

//注销卡
bool DeleteCard(Array_BankCard* parr, const char* idcard) {
	assert(parr != nullptr);
	int i = 0;
	for (; i < parr->cards_size; i++) {
		if (strcmp(parr->cards[i].user.idcard, idcard) == 0) {
			break;
		}
	}
	free(parr->cards->records);
	for (; i < parr->cards_size; i++) {
		parr->cards[i] = parr->cards[i + 1];
	}
	parr->cards_size--;
	return true;
}

(15)结束时销毁数组

//结束销毁数组
void Destroy(Array_BankCard* parr) {
	assert(parr != nullptr);
	free(parr->cards->records);
	free(parr->cards);
	parr->cards->records = nullptr;//防止野指针
	parr->cards = nullptr;//防止野指针
}

四,函数调用

1,前置工作

这里为代码方便使用,我是直接将账号信息数据存贮到文件里去了。

所以在这里需要你们在自己桌面上建立两个文本文档,一个用来存贮管理员账号信息,一个用来存贮银行卡账号信息。

2,atm_op.cpp(引用头文件后的所有函数调用)

(1)从文件中读取管理员身份信息

这里直接把你们自己创建的文件的地址跟我的一替换就行。

//从文件中读取管理员身份信息
void ReadMangerFile(Array_Manager* parr) {
	assert(parr != nullptr);
	FILE* fp;  //用于文件操作
	int i = 0;//初始化,用于确定个数
	//从文件中取出账户信息并存入当前操作系统中
	/*a+:以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF符不保留)。*/
	if ((fp = fopen("C:/Users/123/Desktop/ATM机Manger账号信息存根.txt", "a+")) == NULL)
	{
		printf("数据文件无法打开!\n");//出错预处理
		exit(0);//exit函数直接结束当前进程
	}
	/*fscanf其功能为根据数据格式,从输入流(文件)中读入数据,存储到结构体数组中,遇到空格和换行时结束。*/
	while (fscanf(fp, "%d %d",  &(parr->managers + i)->m_id, &(parr->managers + i)->m_passwd) != EOF)
	{
		i++;
	}
	parr->manager_size = i; 
	fclose(fp);//关闭文件
	return;
}

(2)从文件中读取银行卡身份信息

//从文件中读取银行卡身份信息
void ReadBankCardFile(Array_BankCard* parr) {
	assert(parr != nullptr);
	FILE* fp;  //用于文件操作
	int i = 0;//初始化,用于确定个数
	//从文件中取出账户信息并存入当前操作系统中
	/*a+:以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF符不保留)。*/
	if ((fp = fopen("C:/Users/123/Desktop/ATM机BankCard账号存根.txt", "a+")) == NULL)
	{
		printf("数据文件无法打开!\n");//出错预处理
		exit(0);//exit函数直接结束当前进程
	}
	/*fscanf其功能为根据数据格式,从输入流(文件)中读入数据,存储到结构体数组中,遇到空格和换行时结束。*/
	while (fscanf(fp, "%d %d %s %d %d %lf %d %d %s %s %lld", &(parr->cards + i)->card_id, &(parr->cards + i)->card_passwd, &(parr->cards + i)->create_card_date, 
		&(parr->cards + i)->islocked, &(parr->cards + i)->islost, &(parr->cards + i)->money, &(parr->cards + i)->records_length, 
		&(parr->cards + i)->records_size, &(parr->cards + i)->user.idcard, &(parr->cards + i)->user.name, &(parr->cards + i)->user.phone) != EOF)
	{
		InitRecords(parr->cards + i);
		i++;
	}
	parr->cards_size = i;
	fclose(fp);//关闭文件
	return;
}

(3)将Manager数据保存到文件中

void WriteMangerFile(Array_Manager* parr) {
	assert(parr != nullptr);
	FILE* fp;  //用于文件操作
	int i = 0;
	//保存余额
	/*w:打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。*/
	if ((fp = fopen("C:/Users/123/Desktop/ATM机Manger账号信息存根.txt", "w")) == NULL)
	{
		printf("数据文件无法打开!\n");
		exit(0);//exit函数直接结束当前进程
	}
	for (i = 0; i < parr->manager_size; i++) {
		fprintf(fp, "%d", (parr->managers + i)->m_id);
		fprintf(fp, " %d\n", (parr->managers+ i)->m_passwd);
	}
	fclose(fp);//关闭文件
}

(4)将BankCard数据保存到文件中

void WriteBankCardFile(Array_BankCard* parr) {
	assert(parr != nullptr);
	FILE* fp;  //用于文件操作
	int i = 0;
	//保存余额
	/*w:打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。*/
	if ((fp = fopen("C:/Users/123/Desktop/ATM机BankCard账号存根.txt", "w")) == NULL)
	{
		printf("数据文件无法打开!\n");
		exit(0);//exit函数直接结束当前进程
	}
	for (i = 0; i < parr->cards_size; i++) {
		fprintf(fp, "%d", (parr->cards + i)->card_id);
		fprintf(fp, " %d", (parr->cards + i)->card_passwd);
		fprintf(fp, " %s", (parr->cards + i)->create_card_date);
		fprintf(fp, " %d", (parr->cards + i)->islocked);
		fprintf(fp, " %d", (parr->cards + i)->islost);
		fprintf(fp, " %lf", (parr->cards + i)->money);
		fprintf(fp, " %d", (parr->cards + i)->records_length);
		fprintf(fp, " %d", (parr->cards + i)->records_size);
		fprintf(fp, " %s", (parr->cards + i)->user.idcard);
		fprintf(fp, " %s", (parr->cards + i)->user.name);
		fprintf(fp, " %lld\n", (parr->cards + i)->user.phone);
	}
	fclose(fp);//关闭文件
}

(5)判断是否是管理员

EasyX图形库里面,InputBox这个函数就是弹出一个输入框让你输入,这个是自动识别为字符数组类型的,我这里是用atoi函数强转成的int整型。

MessageBoxA函数就是给一个选项框,MB_OK就是只有一个“确定”选项。

//判断是否是管理员
void IsManger(Array_Manager* parr) {
	assert(parr != nullptr);
	//弹出输入账号窗口界面
	while (true) {
		char buff[128] = { 0 };
		InputBox(buff, 128, "账号");
		int value1 = atoi(buff);
		char buff2[128] = { 0 };
		InputBox(buff2, 128, "密码");
		int value2 = atoi(buff2);
		bool a = LoginManager(parr, value1, value2);
		if (a)
			break;
		else {
			MessageBoxA(NULL, "账号密码有误!是否重输?", "账号密码不正确", MB_OK);//a作为返回值进行确定下一界面的调用
		}
	}
}

(6)判断是否是用户

//判断是否是用户
int IsUser(Array_BankCard* parr) {
	assert(parr != nullptr);
	//弹出输入账号窗口界面
	while (true) {
		char buff[128] = { 0 };
		InputBox(buff, 128, "账号");
		int value1 = atoi(buff);
		char buff2[128] = { 0 };
		InputBox(buff2, 128, "密码");
		int value2 = atoi(buff2);
		int a = LoginCard(parr, value1, value2);
		if (a != -1) {
			return a;
		}
		else {
			MessageBoxA(NULL, "账号密码有误或此卡已丢失上锁!是否重输?", "请确认是否是您的卡", MB_OK);//a作为返回值进行确定下一界面的调用
		}
	}
}

(7)银行卡解锁

//银行卡解锁
bool FindCard(Array_BankCard* parr, int m_id, int m_passwd) {
	assert(parr != nullptr);
	int index = -1;
	for (int i = 0; i < parr->cards_size; i++) {
		if (parr->cards[i].card_id == m_id && parr->cards[i].card_passwd == m_passwd) {
			index = i;
			break;
		}
	}
	if (index != -1) {
		parr->cards[index].islocked = 0;
		parr->cards[index].islocked = 0;
		return true;
	}
	else 
		return false;
}

(8)管理员选项界面

(我觉得我在这里写的注释应该可以看懂吧?)

//管理员选项界面
int Mangeroption() {
	//矩形(多用于按钮) rectangle(起点x, 起点y, 终点x, 终点y) 自带边框填充fillrectangle(同上)
	RECT rect1 = { 110, 210, 165, 230 };
	fillrectangle(110, 210, 165, 230);
	RECT rect2 = { 435, 210, 490, 230 };
	fillrectangle(435, 210, 490, 230);
	RECT rect3 = { 110, 250, 165, 270 };
	fillrectangle(110, 250, 165, 270);
	RECT rect4 = { 435, 250, 490, 270 };
	fillrectangle(435, 250, 490, 270);
	RECT rect5 = { 110, 290, 165, 310 };
	fillrectangle(110, 290, 165, 310);
	settextcolor(BLACK);//设置文字颜色
	settextstyle(15, 5, "楷体");//设置文字大小
	setbkmode(TRANSPARENT);//设置文字透明背景
	//文字存放在矩形中间
	drawtext("注册银行卡", &rect1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("注销银行卡", &rect2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("注册管理员", &rect3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("银行卡解锁", &rect4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("退出登录", &rect5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	//鼠标事件监听 左键 右键
	while (true) {
		MOUSEMSG msg = GetMouseMsg();
		//鼠标操作
		if (msg.x >= 110 && msg.x <= 165 && msg.y >= 210 && msg.y <= 230 && msg.uMsg == WM_LBUTTONDOWN) {
			return 1;
		}
		if (msg.x >= 435 && msg.x <= 490 && msg.y >= 210 && msg.y <= 230 && msg.uMsg == WM_LBUTTONDOWN) {
			return 2;
		}
		if (msg.x >= 110 && msg.x <= 165 && msg.y >= 250 && msg.y <= 270 && msg.uMsg == WM_LBUTTONDOWN) {
			return 3;
		}
		if (msg.x >= 435 && msg.x <= 490 && msg.y >= 250 && msg.y <= 270 && msg.uMsg == WM_LBUTTONDOWN) {
			return 4;
		}
		if (msg.x >= 110 && msg.x <= 165 && msg.y >= 290 && msg.y <= 310 && msg.uMsg == WM_LBUTTONDOWN) {
			return 0;
		}
	}
}

(9)用户选项界面

//用户选项界面
int BankCardoption() {
	RECT rect1 = { 110, 210, 165, 230 };
	fillrectangle(110, 210, 165, 230);
	RECT rect2 = { 435, 210, 490, 230 };
	fillrectangle(435, 210, 490, 230);
	RECT rect3 = { 110, 250, 165, 270 };
	fillrectangle(110, 250, 165, 270);
	RECT rect4 = { 435, 250, 490, 270 };
	fillrectangle(435, 250, 490, 270);
	RECT rect5 = { 110, 290, 165, 310 };
	fillrectangle(110, 290, 165, 310);
	RECT rect6 = { 435, 290, 490, 310 };
	fillrectangle(435, 290, 490, 310);
	RECT rect7 = { 110, 330, 165, 350 };
	fillrectangle(110, 330, 165, 350);
	RECT rect8 = { 435, 330, 490, 350 };
	fillrectangle(435, 330, 490, 350);
	settextcolor(BLACK);//设置文字颜色
	settextstyle(15, 5, "楷体");//设置文字大小
	setbkmode(TRANSPARENT);//设置文字透明背景
	//文字存放在矩形中间
	drawtext("存款", &rect1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("取款", &rect2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("转账", &rect3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("查余额", &rect4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("查开户日期", &rect5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("查流水明细", &rect6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("挂失", &rect7, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("退出", &rect8, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	while (true) {
		MOUSEMSG msg = GetMouseMsg();
		//鼠标操作
		if (msg.x >= 110 && msg.x <= 165 && msg.y >= 210 && msg.y <= 230 && msg.uMsg == WM_LBUTTONDOWN) {
			return 1;
		}
		if (msg.x >= 435 && msg.x <= 490 && msg.y >= 210 && msg.y <= 230 && msg.uMsg == WM_LBUTTONDOWN) {
			return 2;
		}
		if (msg.x >= 110 && msg.x <= 165 && msg.y >= 250 && msg.y <= 270 && msg.uMsg == WM_LBUTTONDOWN) {
			return 3;
		}
		if (msg.x >= 435 && msg.x <= 490 && msg.y >= 250 && msg.y <= 270 && msg.uMsg == WM_LBUTTONDOWN) {
			return 4;
		}
		if (msg.x >= 110 && msg.x <= 165 && msg.y >= 290 && msg.y <= 310 && msg.uMsg == WM_LBUTTONDOWN) {
			return 5;
		}
		if (msg.x >= 435 && msg.x <= 490 && msg.y >= 290 && msg.y <= 310 && msg.uMsg == WM_LBUTTONDOWN) {
			return 6;
		}
		if (msg.x >= 110 && msg.x <= 165 && msg.y >= 330 && msg.y <= 350 && msg.uMsg == WM_LBUTTONDOWN) {
			return 7;
		}
		if (msg.x >= 435 && msg.x <= 490 && msg.y >= 330 && msg.y <= 350 && msg.uMsg == WM_LBUTTONDOWN) {
			return 0;
		}
	}
}

(10)管理员功能选择实现

管理员是最高级权限,可以对银行卡进行销户和注册以及挂失的操作。

再提一嘴,MessageBoxA函数这里MB_YESNO就是有一个“是”选项和一个“否”选项。这里要注意是的话会返回6,否的话会返回7。注意是7不是0!!!

//管理员功能选择实现
void ManagerWork(Array_Manager* parr, Array_BankCard* parr2) {
	assert(parr != nullptr && parr2 != nullptr);
	IsManger(parr);
	while (true) {
		int t = Mangeroption();
		switch (t) {
		case 0:
			break;
		case 1:
		{
			char buff[128] = { 0 };
			InputBox(buff, 128, "账号");
			int id = atoi(buff);
			char buff2[128] = { 0 };
			InputBox(buff2, 128, "密码");
			int passwd = atoi(buff2);
			char buff3[128] = { 0 };
			InputBox(buff3, 128, "金额");
			double money = atof(buff3);
			User user = { NULL, NULL, 0 };
			InputBox(user.name, 128, "姓名");
			InputBox(user.idcard, 128, "身份证号");
			char buff6[128] = { 0 };
			InputBox(buff6, 128, "电话号码");
			user.phone = atoll(buff6);
			bool test = RegisterCard(parr2, id, passwd, money, &user);
			if (test) {
				MessageBoxA(NULL, "恭喜你,注册成功!", "注册成功", MB_OK);
			}
			else {
				MessageBoxA(NULL, "很抱歉,您的身份证已存在一张卡!", "注册失败", MB_OK);
			}
			break;
		}
		case 2:
		{
			char buff4[128] = { 0 };
			InputBox(buff4, 128, "请输入您要注销的账号");
			bool deletecard = DeleteCard(parr2, buff4);
			if (deletecard) {
				MessageBoxA(NULL, "恭喜你,注销成功!", "注销成功", MB_OK);
			}
			else {
				MessageBoxA(NULL, "很抱歉,注销失败,请确认您的卡号是否正确", "注销失败", MB_OK);
			}
			break;
		}
		case 3:
		{
			char buff7[128] = { 0 };
			InputBox(buff7, 128, "账号");
			int id2 = atoi(buff7);
			char buff8[128] = { 0 };
			InputBox(buff8, 128, "密码");
			int passwd2 = atoi(buff8);
			RegisterManager(parr, id2, passwd2);
			MessageBoxA(NULL, "恭喜你,注册成功!", "注册成功", MB_OK);
			break;
		}
		case 4:
		{
			char buff9[128] = { 0 };
			InputBox(buff9, 128, "账号");
			int id3 = atoi(buff9);
			char buff10[128] = { 0 };
			InputBox(buff10, 128, "密码");
			int passwd3 = atoi(buff10);
			bool find = FindCard(parr2, id3, passwd3);
			if (find) {
				MessageBoxA(NULL, "恭喜你,解锁成功!", "解锁成功", MB_OK);
			}
			else {
				MessageBoxA(NULL, "请确认您所输入的账号和密码是否正确!", "解锁失败", MB_OK);
			}
			break;
		}
		}
		if (t != 0) {
			int n = MessageBoxA(NULL, "还有别的服务需求吗?", "ATM机管理员询问", MB_YESNO);//a作为返回值进行确定下一界面的调用
			if (n == 6) {
				continue;
			}
			else break;
		}
		else break;
	}
}

(11)用户功能选择实现

//用户功能选择实现
void BankCardWord(Array_BankCard* parr) {
	assert(parr != nullptr);
	int index = IsUser(parr);
	while (true) {
		int t = BankCardoption();
		switch (t) {
		case 0:
			break;
		case 1:
		{
			char buff[128] = { 0 };
			InputBox(buff, 128, "金额");
			double money = atof(buff);
			bool save = SaveMoney(parr, index, money);
			if (save) {
				MessageBoxA(NULL, "恭喜你,存款成功!", "存款", MB_OK);
			}
			else {
				MessageBoxA(NULL, "很抱歉,存款失败!", "存款失败", MB_OK);
			}
			break;
		}
		case 2:
		{
			char buff2[128] = { 0 };
			InputBox(buff2, 128, "金额");
			double money2 = atof(buff2);
			bool get = Withdraw(parr, index, money2);
			if (get) {
				MessageBoxA(NULL, "恭喜你,取款成功!", "取款", MB_OK);
			}
			else {
				MessageBoxA(NULL, "您的余额不足,取款失败!", "取款失败", MB_OK);
			}
			break;
		}
		case 3:
		{
			char buff3[128] = { 0 };
			InputBox(buff3, 128, "请输入你要转向的账户");
			int userid = atoi(buff3);
			char buff4[128] = { 0 };
			InputBox(buff4, 128, "金额");
			double money3 = atof(buff4);
			bool tranfer = Transfer(parr, index, userid, money3);
			if (tranfer) {
				MessageBoxA(NULL, "恭喜你,转账成功!", "转账", MB_OK);
			}
			else {
				MessageBoxA(NULL, "您的余额不足或不存在该账户,转账失败!", "转账失败", MB_OK);
			}
			break;
		}
		case 4:
			GetMoney(parr, index);
			break;
		case 5:
		{
			char* create = GetCretCarDate(parr, index);
			int i = 0;
			for (; i < 8; i++) {
				printf("%c", *(create + i));
			}
			printf(" ");
			for (; i < strlen(parr->cards[index].create_card_date); i++) {
				printf("%c", *(create + i));
			}
			printf("\n");
			break;
		}
		case 6:
			GetWaterMessage(parr, index);
			break;
		case 7:
		{
			bool lost = Lost(parr, index);
			if (lost) {
				MessageBoxA(NULL, "不用担心,已将您挂失的卡成功上锁!", "挂失", MB_OK);
			}
			else {
				MessageBoxA(NULL, "很抱歉,挂失失败!", "挂失失败", MB_OK);
			}
			break;
		}
		}
		if (t != 0) {
			int n = MessageBoxA(NULL, "还有别的服务需求吗?", "ATM机管理员询问", MB_YESNO);//a作为返回值进行确定下一界面的调用
			if (n == 6) {
				continue;
			}
			else break;
		}
		else break;
	}
}

(12)打开atm机窗口

initgraph函数就是建立一个图形化窗口。

SHOWCONSOLE就是把控制台也展示出来。

image在这里简单理解就是贴了个图,图片就是前面放的那张ATM机的图片,直接下载就好,如果你要用自己的图那么我只能祝你好运了(因为我前面有关选项按钮的设置是根据我自己的图打的点,打点本身其实不难,数学功底够硬就好,主要还是一个点一个点打的太麻烦,懒人直接下载我的图就好)。

//打开atm机窗口
void Put_initgraph(Array_Manager* parr, Array_BankCard* parr2) {
	assert(parr != nullptr && parr2 != nullptr);
	//BGM();
	initgraph(600, 700, SHOWCONSOLE);
	IMAGE image;
	loadimage(&image, "F:/微信图片_20230218171935.jpg", 600, 700, true);
	putimage(0, 0, &image);
	while (true) {
		int m = MessageBoxA(NULL, "你是管理员吗?", "ATM识别身份", MB_YESNO);//a作为返回值进行确定下一界面的调用
		if (m == 6) {
			ManagerWork(parr, parr2);
			int next = MessageBoxA(NULL, "是否需要更换身份?选否则运行结束", "登录", MB_YESNO);
			cleardevice();//清屏
			loadimage(&image, "F:/微信图片_20230218171935.jpg", 600, 700, true);
			putimage(0, 0, &image);
			if (next == 6)
				continue;
			else
				break;
		}
		else {
			int u = MessageBoxA(NULL, "你是用户吗?", "ATM识别身份", MB_YESNO);//a作为返回值进行确定下一界面的调用
			if (u == 6) {
				BankCardWord(parr2);
				int next2 = MessageBoxA(NULL, "是否需要更换身份?选否则运行结束", "登录", MB_YESNO);
				cleardevice();//清屏
				loadimage(&image, "F:/微信图片_20230218171935.jpg", 600, 700, true);
				putimage(0, 0, &image);
				if (next2 == 6)
					continue;
				else
					break;
			}
			else {
				MessageBoxA(NULL, "你绝对是选错了,没有第三个身份。", "逗我玩呢?", MB_OK);
			}
		}
	}
	system("pause");//按任意键继续
	closegraph();//关闭窗口
}

3,main主函数

int main() {
	Array_Manager managers;
	InitManagers(&managers);
	ReadMangerFile(&managers);
	Array_BankCard bankcards;
	InitCardArray(&bankcards);
	ReadBankCardFile(&bankcards);
	Put_initgraph(&managers, &bankcards);
	WriteMangerFile(&managers);
	DestoryManagers(&managers);
	WriteBankCardFile(&bankcards);
	Destroy(&bankcards);
	return 0;
}

五,心得总结

作为c语言的练习代码,其中封装函数和调用函数是必须要掌握的基础知识,相较于我大学时写的简易版的银行账户管理系统,我现在这个版本也只是加上了EasyX库的图形调用。

整体上来说功能模块完成的还算完整,缺点是没有对卡的流水记录进行文件存贮,会导致重新运行时数据的丢失(不过问题不大,只要你学会了文件读写操作,就是多谢一部分代码的事)。

整体代码量比较长,但是为了功能完整性,还是只能写这么多

 最后:

(本文仅供学习时参考,如有错误,纯属作者技术不到位,不足之处请多指教,勿喷,谢谢)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐