目录
一、题目描述
实现一个银行存取款管理系统,实现如下功能:
功能1:客户信息录入、包括编号、客户姓名、支取密码、客户地址、客户电话、账户金额; 功能2:存取款信息录入:即添加编号、日期、类别、存取数目、经办人;
功能3:根据客户信息查询存取款记录;客户信息和存取款信息的修改,删除;
功能4:信息保存、系统、退出;
二、程序思路
2.1 题目分析
要实现银行存取款管理系统,首先,我们应该想到定义一个结构体,包含姓名、卡号、地址等等个人信息,每一个客户就是一个结构体。那么所有客户信息、客户存取款记录应该怎么存呢?在本程序中我是用了两个动态扩容的顺序表存储的,客户信息按时间顺序连续存储在内存中,每一个客户的存取款记录也是连续存储的,当然,也可以使用两个链表是实现,并无多大差别,这些信息在退出程序时都应保存在文件中。
2.2 功能分析
能够输入和查询客户存款取款记录。在客户文件中,每个客户是一条记录,包括编号、客户姓名、支取密码、客户地址、客户电话、账户总金额;在存取款文件中,每次存取款是一条记录,包括编号、日期、类别、存取数目、经办人。类别分为取款和存款两种。本系统能够输入客户存款或取款记录;根据客户姓名查询存款和取款记录。
分步实施:
1、初步完成总体设计,搭好框架,确定人机对话界面,确定函数个数;
2、建立一个文件,输入客户的必要信息,能对文件进行显示、输入、修订、删除等。
3、进一步要求:完成客户姓名查询存款和取款记录,并能得到每次帐户总金额。
2.3 程序设计
定义三个结构体,第一个结构体是一个人所包含的信息;第二个结构体是一个用户的存取款记录;第三个结构体是以上述两种结构体为类型创建的两个顺序表用于存储完整的的客户信息。再实现相应功能对应的函数、系统界面、文件加载保存等等即可。
三、程序实现代码
3.1 bank.h
#pragma once
#include<stdio.h>
#include<time.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#define INIT_CAPACITY 100
#define NAME_MAX 20
#define PASSWORD_MAX 6
#define ADDR_MAX 20
#define TELE_MAX 12
#define TIME_MAX 30
#define CURRENCY_MAX 3//注意大小要给到3以上,而不是2,否则会存不下,出现未知错误
#define CARD_MAX 16
#define ACTION_MAX 2
enum Option
{
ExitSystem,//0
OpenAccount,//1
QueryAccount,//2
Deposit,//3
Withdrawal,//4
LoginSystem,//5
};
enum Choose
{
Dollar = 1,
RWB,
Pound,
Euro,
};
enum Modify
{
ExitModify,
Name,
Card,
Telephone,
Address,
};
enum Manager
{
ExitManager,
PrintBank,
ModifyPeople,
DeletePeople,
};
typedef struct PeoInfo
{
char name[NAME_MAX];
char card[CARD_MAX];
char tele[TELE_MAX];
char addr[ADDR_MAX];
char time[TIME_MAX];
char currency[CURRENCY_MAX];
char password[PASSWORD_MAX];
int balance;
}PeoInfo;
typedef struct Record
{
char action[ACTION_MAX];
char time[TIME_MAX];
int money;
int src;//记录起始存取款位置
int count;//记录每一个人存取款的次数
}Record;
typedef struct Bank
{
PeoInfo* data;
Record* record;
int sz_bank;//记录系统中的人数
int capacity_bank;//记录人数可用容量
int sz_record;//记录存取款次数
int capacity_record;//记录存取款可用容量
}Bank;
//初始化银行存取款系统
void Init_bank(Bank* pb);
//开户
void open_account(Bank* pb);
//查询账户
void query_account(const Bank* pb);
//存款
void deposit(Bank* pb);
//取款
void withdrawal(Bank* pb);
//管理员登录
void login_system(Bank* pb);
//退出时保存数据
void save_bank(const Bank* pb);
//退出时销毁系统,释放空间
void destroy_bank(Bank* pb);
3.2 bank.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"bank.h"
//扩大系统人数容量
void check_bank_capacity(Bank* pb)
{
assert(pb);
if (pb->sz_bank == pb->capacity_bank)
{
PeoInfo* tmp = (PeoInfo*)realloc(pb->data, (pb->capacity_bank * 2) * sizeof(PeoInfo));
//判断是否扩容成功再将空间首地址赋给pc->data
if (tmp != NULL)
{
pb->data = tmp;
pb->capacity_bank *= 2;
printf("扩容成功!\n");
}
else
{
perror("check_bank_capacity::realloc");
}
}
}
//扩大存取款记录容量
void check_record_capacity(Bank* pb)
{
assert(pb);
if (pb->sz_record == pb->capacity_record)
{
Record* tmp = (Record*)realloc(pb->record, (pb->capacity_record * 2) * sizeof(Record));
if (tmp != NULL)
{
pb->record = tmp;
pb->capacity_record *= 2;
}
else
{
perror("check_record_capacity::realloc");
}
}
}
//加载文件数据
void load_bank(Bank* pb)
{
assert(pb);
FILE* pf1 = fopen("Bank.txt", "r");
if (pf1 == NULL)
{
perror("load_bank::Bank");
return;
}
PeoInfo tmp1 = { 0 };
while (fread(&tmp1, sizeof(PeoInfo), 1, pf1))
{
check_bank_capacity(pb);
pb->data[pb->sz_bank] = tmp1;
pb->sz_bank++;
}
FILE* pf2 = fopen("Record.txt", "r");
if (pf2 == NULL)
{
perror("load_bank::Record");
return;
}
Record tmp2 = { 0 };
while (fread(&tmp2, sizeof(Record), 1, pf2))
{
check_record_capacity(pb);
pb->record[pb->sz_record] = tmp2;
pb->sz_record++;
}
}
//初始化银行管理系统
void Init_bank(Bank* pb)
{
assert(pb);//断言
pb->sz_bank = 0;
pb->capacity_bank = INIT_CAPACITY;//起始的容量
pb->data = (PeoInfo*)malloc(pb->capacity_bank * sizeof(PeoInfo));
if (pb->data == NULL)//判空
{
perror("InitBank::malloc");
return;
}
else
{
pb->data[pb->sz_bank].balance = 0;
memset(pb->data, 0, pb->capacity_bank * sizeof(PeoInfo));
}
pb->sz_record = 0;
pb->capacity_record = INIT_CAPACITY;
pb->record = (Record*)malloc(pb->capacity_record * sizeof(Record));
if (pb->record == NULL)
{
perror("InitBank::malloc");
return;
}
else
{
//注意不能放在if之前初始化,因为if之前空间还未开辟不能使用
pb->record[pb->sz_bank].count = 0;
pb->record[pb->sz_bank].src = 0;
memset(pb->record, 0, pb->capacity_record * sizeof(Record));
//从文件加载数据
load_bank(pb);
}
}
//检查姓名输入
int check_name(const char* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
if (((arr[i] >= 0) && (arr[i] <= 64)) || ((arr[i] >= 123) && (arr[i] <= 127)))
{
printf("非法输入,姓名只能为汉字和英文!\n");
return 0;
}
}
return 1;
}
//检查电话输入
int check_tele(const char* arr, int sz)
{
for (int i = 0; i < sz; i++)
{
if (isdigit(arr[i]) == 0)
{
printf("非法输入,请输入纯数字!\n");
return 1;
}
}
return 0;
}
//查找客户
int find_account(const Bank* pb, const char* card)
{
assert(pb && card);
for (int i = 0; i < pb->sz_bank; i++)
{
if (strcmp(pb->data[i].card, card) == 0)
{
return i;//找到
}
}
return -1;//找不到
}
//检查卡号
int check_card(const Bank* pb)
{
assert(pb);
int pos = 0;
char card[CARD_MAX] = { 0 };
do
{
printf("请输入账户卡号:>");
scanf("%s", card);
pos = find_account(pb, card);//找不到是-1
if (pos == -1)
{
printf("卡号错误,请重新输入!\n");
}
else
{
return pos;//卡号正确返回下标
}
} while (pos == -1);
return -1;
}
//检查密码
int check_password(const Bank* pb, const int pos)
{
assert(pb);
char password[PASSWORD_MAX] = { 0 };
int count = 3;
while (count > 0)
{
printf("请输入密码(您还有%d次机会):>", count);
scanf("%s", password);
if (strlen(pb->data[pos].password) != strlen(password))
{
if (count == 1)//注意此处是1而不是0,因为1已经是最后一次输密码了
{
return 0;//错误返回0
}
else
{
printf("密码错误,请重新输入!\n");
}
}
else
{
if (strcmp(pb->data[pos].password, password) == 0)
{
return 1;//正确返回1
}
else
{
if (count == 1)//注意此处是1而不是0,因为1已经是最后一次输密码了
{
return 0;//错误返回0
}
else
{
printf("密码错误,请重新输入!\n");
}
}
}
count--;
}
return 0;
}
//获取时间
char* get_time()//char* ctime( const time_t *timer );
{
time_t t = 0;
t = time(NULL);
char* time = ctime(&t);
return time;
}
//开户
void open_account(Bank* pb)
{
assert(pb != NULL);
check_bank_capacity(pb);
int ret = 0;
printf("欢迎开户!\n");
label:
printf("请输入您的姓名:>");
scanf("%s", pb->data[pb->sz_bank].name);
int sz_name = strlen(pb->data[pb->sz_bank].name);
if (check_name(pb->data[pb->sz_bank].name, sz_name) == 0)
{
goto label;
}
label1:
printf("请输入四位电话:>");
scanf("%s", pb->data[pb->sz_bank].tele);
int sz_tele = strlen(pb->data[pb->sz_bank].tele);
ret = check_tele(pb->data[pb->sz_bank].tele, sz_tele);
if (ret == 1)
{
goto label1;
}
if (sz_tele != 4)
{
printf("您的手机位数不足或多余四位,请重新设置\n");
goto label1;
}
printf("请输入您的地址:>");
scanf("%s", pb->data[pb->sz_bank].addr);
label2:
printf("请设置四位卡号:>");
scanf("%s", pb->data[pb->sz_bank].card);
int sz_card = strlen(pb->data[pb->sz_bank].card);
ret = check_tele(pb->data[pb->sz_bank].card, sz_card);
if (ret == 1)
{
goto label2;
}
if (sz_card != 4)
{
printf("您的卡号不足四位或多余四位,请重新设置卡号\n");
goto label2;
}
for (int i = 0; i < pb->sz_bank; i++)
{
if (strcmp(pb->data[pb->sz_bank].card, pb->data[i].card) == 0)
{
printf("此卡号已存在,请重新设置卡号\n");
goto label2;
}
}
printf("请设置您的密码:>");
scanf("%s", pb->data[pb->sz_bank].password);
char* src = get_time();
strcpy(pb->data[pb->sz_bank].time, src);
pb->record[pb->sz_bank].src = pb->sz_record;//记录客户起始存取款位置
pb->sz_bank++;
printf("开户成功!\n");
}
//判断位数
int digit(int m)
{
int n = 0;
while (m > 0)
{
n++;
m /= 10;
}
return n;
}
//打印客户信息
void print_peoinfo(const Bank* pb, int pos)
{
assert(pb);
int n1 = digit(pb->data[pos].balance);
printf("您的信息为:\n");
printf("%-15s %-15s %-15s %-15s %-15s %-15s\n", "Name", "Card", "Telephone", "Address", "Balance", "OpenDate");
printf("%-15s %-15s %-15s %-15s %d%s", pb->data[pos].name, pb->data[pos].card, pb->data[pos].tele, pb->data[pos].addr, pb->data[pos].balance, pb->data[pos].currency);
if (pb->data[pos].balance == 0)
{
printf(" ");
}
for (int i = 0; i < 15 - n1 - 1; i++)
{
printf(" ");
}
printf("%-15s\n", pb->data[pos].time);
//询问是否需要查询存取记录
int input = 0;
printf("*************************************************************************\n");
printf("*************************** 1.Yes 0.No ******************************\n");
printf("*************************************************************************\n");
printf("请问您是否需要查询存取款记录:>");
scanf("%d", &input);
if (input == 0)
{
return;
}
else
{
if (pb->record[pos].count == 0)
{
printf("暂无存取款记录!\n");
return;
}
else
{
printf("%-15s %-15s %-15s %-15s\n", "Number", "Name", "Action", "Date");
int j = 1;
for (int i = pb->record[pos].src; i < pb->record[pos].count + pb->record[pos].src; i++)
{
int n2 = digit(pb->record[i].money);
printf("%-15d %-15s %s%d", j++, pb->data[pos].name, pb->record[i].action, pb->record[i].money);
for (int k = 0; k < 15 - n2; k++)
{
printf(" ");
}
printf("%-15s\n", pb->record[i].time);
}
}
}
}
//客户登录
int log_in(const Bank* pb)
{
assert(pb);
if (pb->sz_bank == 0)
{
printf("当前无用户,请先开户!\n");
return 0;
}
int pos = check_card(pb);
int ret = check_password(pb, pos);
if (ret)
{
return pos;//密码正确,返回客户下标
}
else
{
return -1;//密码错误,登录失败返回-1
}
}
//查询账户
void query_account(const Bank* pb)
{
assert(pb);
if (pb->sz_bank == 0)
{
printf("系统暂无用户,无法查询,请先开户\n");
return;
}
if (pb->sz_bank == 0)
{
printf("银行存取款管理系统为空,无法查询!\n");
return;
}
int pos = log_in(pb);
if (pos != -1)//登录失败返回-1
{
print_peoinfo(pb, pos);
}
}
//货币菜单
void menu_currency()
{
printf("*************************************************************************\n");
printf("************************** 1.Dollar 2.RWB ***************************\n");
printf("************************** 3.Pound 4.Euro ***************************\n");
printf("*************************************************************************\n");
}
//存取款记录插入
void record_insert(Bank* pb, int pos)
{
assert(pb);
for (int i = 0; i < pb->sz_bank; i++)
{
if (strcmp(pb->data[pos].card, pb->data[i].card) == 0)
{
int end = pb->sz_record - 1;
while (end >= pb->record[pos].src + pb->record[pos].count)
{
pb->record[end + 1] = pb->record[end];
end--;
}
//插入后需更新pos后的人的初始存取款位置
for (int j = pos + 1; j < pb->sz_bank; j++)
{
pb->record[j].src++;
}
}
}
}
//存款
void deposit(Bank* pb)
{
assert(pb);
if (pb->sz_bank == 0)
{
printf("系统暂无用户,无法存款,请先开户\n");
return;
}
check_record_capacity(pb);
int pos = log_in(pb);
if (pos == -1)
{
return;//登录失败
}
int choose = 0;
menu_currency();
label:
printf("请选择货币:>");
scanf("%d", &choose);
switch (choose)
{
case Dollar:
strcpy(pb->data[pos].currency, "$");//不能用符号
break;
case RWB:
strcpy(pb->data[pos].currency, "¥");
break;
case Pound:
strcpy(pb->data[pos].currency, "£");
break;
case Euro:
strcpy(pb->data[pos].currency, "€");
break;
default:
printf("输入错误,请重新输入!\n");
goto label;
}
//同一个人存取款应是连续存放的,需要插入之前存储的位置
record_insert(pb, pos);
int money = 0;
printf("请输入存款金额:>");
scanf("%d", &money);
pb->record[pb->record[pos].src + pb->record[pos].count].money = money;
pb->data[pos].balance += money;
//strcpy(pb->record[pb->sz_record].action, "+");
strcpy(pb->record[pb->record[pos].src + pb->record[pos].count].action, "+");
char* src = get_time();
strcpy(pb->record[pb->record[pos].src + pb->record[pos].count].time, src);
pb->record[pos].count++;//记录存取款次数
pb->sz_record++;
printf("存款成功!\n");
}
//取款
void withdrawal(Bank* pb)
{
assert(pb);
if (pb->sz_bank == 0)
{
printf("系统暂无用户,无法存款,请先开户\n");
return;
}
check_record_capacity(pb);
int pos = log_in(pb);
if (pos == -1)
{
return;//登录失败
}
//同一个人存取款应是连续存放的,需要插入之前存储的位置
record_insert(pb, pos);
int money = 0;
printf("请输入取款金额:>");
scanf("%d", &money);
if (pb->data[pos].balance < money)
{
printf("账户余额不足,取款失败\n");
return;
}
pb->record[pb->record[pos].src + pb->record[pos].count].money = money;
pb->data[pos].balance -= money;
strcpy(pb->record[pb->record[pos].src + pb->record[pos].count].action, "-");
char* src = get_time();
strcpy(pb->record[pb->record[pos].src + pb->record[pos].count].time, src);
pb->record[pos].count++;//记录存取款次数
pb->sz_record++;
printf("取款成功!\n");
}
//管理员菜单
void menu_manager()
{
printf("*************************************************************************\n");
printf("************************** 1.PrintBank ****************************\n");
printf("************************** 2.ModifyPeople ****************************\n");
printf("************************** 3.DeletePeople ****************************\n");
printf("************************** 0.ExitManager ****************************\n");
printf("*************************************************************************\n");
}
void menu_modify()
{
printf("*************************************************************************\n");
printf("************************** 1.Name 2.Card ********************\n");
printf("************************** 3.Telephone 4.Address ********************\n");
printf("************************** 0.ExitModify ********************\n");
printf("*************************************************************************\n");
}
//管理员打印
void print_bank(Bank* pb)
{
assert(pb);
if (pb->sz_bank == 0)
{
printf("系统中暂无客户,无法打印\n");
return;
}
printf("银行客户信息为:\n");
printf("%-15s %-15s %-15s %-15s %-15s %-15s\n", "Name", "Card", "Telephone", "Address", "Balance", "OpenDate");
for (int i = 0; i < pb->sz_bank; i++)
{
int n1 = digit(pb->data[i].balance);
printf("%-15s %-15s %-15s %-15s %d%s", pb->data[i].name, pb->data[i].card, pb->data[i].tele, pb->data[i].addr, pb->data[i].balance, pb->data[i].currency);
if (pb->data[i].balance == 0)
{
printf(" ");
}
for (int j = 0; j < 15 - n1 - 1; j++)
{
printf(" ");
}
printf("%-15s\n", pb->data[i].time);
}
}
//管理员修改客户信息
void modify_bank(Bank* pb)
{
assert(pb);
if (pb->sz_bank == 0)
{
printf("系统暂无客户,无法修改!\n");
return;
}
int pos = check_card(pb);
int input = 0;
do
{
menu_modify();
printf("请选择要修改的信息:>");
scanf("%d", &input);
switch (input)
{
case Name:
printf("请输入新的名字:>");
scanf("%s", pb->data[pos].name);
printf("修改成功!\n");
break;
case Card:
printf("请设置新的卡号:>");
scanf("%s", pb->data[pos].card);
printf("修改成功!\n");
break;
case Telephone:
printf("请输入新的电话:>");
scanf("%s", pb->data[pos].tele);
printf("修改成功!\n");
break;
case Address:
printf("请输入新的地址:>");
scanf("%s", pb->data[pos].addr);
printf("修改成功!\n");
break;
case ExitModify:
break;
default:
printf("输入错误!请重新输入:>");
break;
}
} while (input);
}
//管理员删除客户
void delete_people(Bank* pb)
{
assert(pb);
if (pb->sz_bank == 0)
{
printf("系统暂无客户,无法删除!\n");
return;
}
int pos = check_card(pb);
for (int i = pos; i < pb->sz_bank - 1; i++)
{
pb->data[i] = pb->data[i + 1];
}
pb->sz_bank--;
pb->data[pos].balance = 0;
strcpy(pb->data[pos].currency, "\0");
///*删除客户时客户的存取款记录也得删
//注意循环删除,要不然会只删除第一次存取款的记录,
//其他记录会出现在下一次开户查询中*/
//while (pb->sz_record)
//{
// for (int j = pos; j < pb->sz_record - 1; j++)
// {
// pb->record[j] = pb->record[j + 1];
// }
// pb->sz_record--;
//}
printf("该客户及其存取款记录已删除成功!\n");
}
//管理员登录
void login_system(Bank* pb)
{
assert(pb);
char password[] = "123";
char input[PASSWORD_MAX] = { 0 };
int count = 3;
printf("请输入银行存取款系统管理员密码:>");
while (count)
{
scanf("%s", input);
if (strlen(password) != strlen(input))
{
printf("密码错误,请重新输入!\n");
count--;
}
else
{
if (strcmp(password, input) != 0)
{
printf("密码错误,请重新输入!\n");
count--;
}
else
{
printf("欢迎管理员登录!\n");
break;
}
}
}
int choose = 0;
do
{
menu_manager();
printf("请选择:>");
scanf("%d", &choose);
switch (choose)
{
case PrintBank:
print_bank(pb);
break;
case ModifyPeople:
modify_bank(pb);
break;
case DeletePeople:
delete_people(pb);
break;
case ExitManager:
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (choose);
}
//保存数据到文件
void save_bank(const Bank* pb)
{
assert(pb);
//打开文件
FILE* pf1 = fopen("Bank.txt", "w");
if (pf1 == NULL)
{
perror("save_bank::fopen");
return;
}
//写文件
for (int i = 0; i < pb->sz_bank; i++)
{
fwrite(pb->data + i, sizeof(PeoInfo), 1, pf1);
}
//关闭文件
fclose(pf1);
pf1 = NULL;
FILE* pf2 = fopen("Record.txt", "w");
if (pf2 == NULL)
{
perror("save_record::fopen");
return;
}
for (int j = 0; j < pb->sz_record; j++)
{
fwrite(pb->record + j, sizeof(Record), 1, pf2);
}
fclose(pf2);
pf2 = NULL;
printf("数据已保存\n");
}
//退出时销毁系统
void destroy_bank(Bank* pb)
{
assert(pb);
free(pb->data);
free(pb->record);
pb->data = NULL;
pb->record = NULL;
pb->sz_bank = 0;
pb->sz_record = 0;
pb->capacity_bank = 0;
pb->capacity_record = 0;
}
3.3 test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"bank.h"
void menu()
{
printf("*************************************************************************\n");
printf("********* Welcome to the bank deposit and withdrawal system *********\n");
printf("************************** 1.OpenAccount ***************************\n");
printf("************************** 2.QueryAccount ***************************\n");
printf("************************** 3.Deposit ***************************\n");
printf("************************** 4.Withdrawal ***************************\n");
printf("************************** 5.LoginSystem ***************************\n");
printf("************************** 0.ExitSystem ***************************\n");
printf("*************************************************************************\n");
}
void test()
{
int input = 0;
Bank bank;
Init_bank(&bank);
do
{
menu();
printf("请选择:>");
if (scanf("%d", &input) == EOF)
{
printf("输入错误\n");
break;
}
fflush(stdin);
switch (input)
{
case OpenAccount:
open_account(&bank);
system("pause");
system("cls");
break;
case QueryAccount:
query_account(&bank);
system("pause");
system("cls");
break;
case Deposit:
deposit(&bank);
system("pause");
system("cls");
break;
case Withdrawal:
withdrawal(&bank);
system("pause");
system("cls");
break;
case LoginSystem://管理员初始密码为123
login_system(&bank);
system("pause");
system("cls");
break;
case ExitSystem:
save_bank(&bank);//退出时保存数据
destroy_bank(&bank);//退出时销毁系统
break;
default:
printf("输入错误,请重新输入!\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
四、结语
编码不易,码字不易,如果对你有所帮助的话,不妨点个小小的赞吧,thank you~