功能说明:
1.完成注册功能:输入账号和密码登录
2.完成登录功能:输入账号和密码注册
3.成功登陆后,实现存款
4.成功登陆后,实现取款
5.成功登陆后,实现转账
6.成功登陆后,实现查询余额
7.退卡
代码解析:
1.完成登录功能:输入账号和密码登录
先查找是否有该账号,如果查找不到账号或者密码输入错误,打印“登陆失败”。
查找到该账号并且密码匹配,打印“登陆成功”。
2.完成注册功能:输入账号和密码注册
先检查该账号和密码是否已经注册过,如已注册,打印“注册失败”。
如未注册过,检查内存是否满了,如果内存满了需要进行扩容操作。
未满\扩容之后,将注册的账号和密码进行存储,并打印“注册成功”。
3.完成登陆成功后的功能:输入要操作的账号和密码进行登录。
存款:对已经登陆成功的卡进行原余额+新存入的钱,并通过查询余额进行验证
取款:对已经登陆成功的卡进行原余额-新存入的钱,并通过查询余额进行验证;如果待取金额>原余额,则取款失败,否则,成功。
转账:对已经登陆成功的卡进行原余额-待转账的钱,并通过查询余额进行验证;如果待取金额>原余额,则转账失败;通过输入另一账号对待接收转账金额的卡进行查找,如果该卡不存在,则转账失败;
查询余额:输出当前卡余额
函数设计:
首先建立结构体,对卡槽的卡进行存储,以及卡的账户密码余额信息存储。
typedef struct BankCard {//存放卡的信息
int id; //账户
int password;//密码
double money;//余额
}BankCard;//BankCard=struct BankCard
typedef struct Array {//卡槽,存放卡
BankCard* cards;//该数组存放卡
int size;//记录有效卡个数,可以理解为实际占用的数组内存个数
int length;//记录当前数组cards大小,动态开辟的内存大小
}Array,*PArr; //Array=struct Array,PArr=struct Array*
说明:BankCard* cards:写成BankCard cards[size];不对,因为[]内只能是常量,而指针就比较OK,可以动态内存开辟存储信息。
完整代码:
头文件
atm.h
#pragma once //可以防止头文件被编译多次
typedef struct BankCard {//银行卡类型
int id;
int password;
double money;
}BankCard;
typedef struct Array {
int size;//记录有效卡个数,可以理解为实际占用的数组内存个数
BankCard* cards;
int length;//记录当前数组cards大小
BankCard* temp;//后面代码扩容函数时需要一个替代量,无其他含义
}Array, * PArr; //PArr=struct Array* parray
//功能函数声明
void init(PArr parray, int len);//初始化Array
int search_card(PArr parray, int id, int password);//查找卡
int login_user(PArr parray, int id, int password); //登录
bool is_full(PArr parray);//对数组判满操作
void grow(PArr parray);//如果满了,扩容
bool register_card(PArr parray, int id, int password);//注册
void destory(PArr parray);//销毁函数
void after_login_success(PArr parray, int index);//登陆成功后的操作,index是当前卡
.cpp
#define _CRT_SECURE_NO_WARNINGS
#include"atm.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//函数声明
void init(PArr parray, int len)//初始化Array
{
assert(parray != NULL);
parray->cards = (BankCard*)malloc(sizeof(BankCard) * len); //或者写成(*parray).cards
assert(parray->cards != NULL);
parray->size = 0;
parray->length = len;
parray->cards->money = 0;
}
//查找卡函数
int search_card(PArr parray, int id, int password)
{
/*实现的操作:去判断该卡的id和密码是否与卡槽里面拥有的卡和密码对应
循环实现,拿卡槽内的卡和密码一张行比较*/
for (int i = 0; i < parray->size; i++)//parray->length是总长,size是有效卡数
{
BankCard curcard = parray->cards[i];//curcard是卡槽的卡,对其初始化
if (curcard.id == id && curcard.password == password) {
return i;//查找成功,返回卡所在下标
}
}
return -1;//没有卡返回-1
}
//登录
int login_user(PArr parray, int id, int password)
{
/*操作:用户输入账号和密码(这个在菜单界面会显示提醒,在这儿不用写),
系统进行卡的查找工作,如果查找成功继续访问,查找失败重新输入*/
assert(parray != NULL);
int index = search_card(parray, id, password);
return index;//返回下标值
}
//对数组判满操作
bool is_full(PArr parray)
{
assert(parray != NULL);
//什么情况下数组是满的?数组开辟总长度==目前数组格子被占用的长度。size==length
return parray->size == parray->length ? true : false;
}
//如果满了,扩容1.5倍
void grow(PArr parray)
{
assert(parray != NULL);
/*以下几种错误解析:
1.int newlength =(int) parray->length + 0.5 * parray->length;
等号右边是double类型,强转为int会出问题,比如扩为1.3,强转:1.
2.对于位运算的使用(如下一行代码所示),/2:右移一位。格子里剔除掉最后一位
位运算优先级小于+。对0.5和2一定要敏感,大多数情况需要使用位运算,而且不会出错 */
int newlength = parray->length + (parray->length >> 1);
parray->temp = (BankCard*)realloc(parray->cards, newlength *
sizeof(BankCard));//realloc扩容的是字数,不是字节数
if (parray->temp != NULL)//如果为NULL,则原来cards所指向的内容无法释放
parray->cards = parray->temp;//该两行代码等同于assert(parray->cards != NULL);
parray->length = newlength;//更新length
}
//注册
bool register_card(PArr parray, int id, int password)
{
assert(parray != NULL);
//查找是否有相同的id和password,如有不能再重复注册
if (search_card(parray, id, password) != -1)//if (search_card(parray, id, password))
return false;
//这个函数内需要用到判满操作
if (is_full(parray))//如果满,扩容
grow(parray);
//此时数组长度已经够了,放入id和password到卡包内
BankCard card = { id,password,0.0 };//新卡余额为0
parray->cards[parray->size] = card;
parray->size++;
return true;
}
//登陆成功后的操作
void after_login_success(PArr parray, int index)
{
int choice;
int id, password;
double money;
int Otherid;
while (true)
{
printf("1.存款 2.取款 3.转账 4.查余额 5.退卡\n");
//下面的代码写到头文件内不好,因为是在一个函数内部实现的
printf("1.存款 2.取款 3.转账 4.查余额 5.退卡");
scanf("%d", &choice);
if (choice == 5)
break;
switch (choice)
{
case 1://存款
printf("请输入存款金额:\n");
scanf("%lf", &money);
parray->cards[index].money += money;
printf("存款成功\n");
break;
case 2://取款
printf("请输入取款金额:\n");
scanf("%lf", &money);
if (parray->cards[index].money >= money) {
parray->cards[index].money -= money;
//等价于(*parray).cards[index].money -= money;
printf("取款成功\n");
}
else
printf("取款失败\n");
break;
case 3://转账
printf("请输入对方转账账号:\n");
scanf("%d", &id);
printf("请输入密码:\n");
scanf("%d", &password);
Otherid = search_card(parray, id, password);
//查找该用户是否存在
if (Otherid == -1)//if (search_card(parray, id, password))
printf("不存在该用户\n");
else
{
printf("请输入转账金额:\n");
scanf("%lf", &money);
//前提转出去的金额所在卡余额应大于转出的钱
if (parray->cards[index].money >= money)
{
parray->cards[index].money -= money;
parray->cards[Otherid].money += money;
printf("转账成功!\n");
}
else
printf("余额不足,转账失败!\n");
}
break;
case 4://显示卡余额
printf("当前卡的余额是:%lf\n", parray->cards[index].money);
break;
}
}
}
//销毁函数
void destory(PArr parray)
{
if (parray == NULL)
return;
free(parray->cards);//释放一维数组
parray->cards = NULL;
}
.cpp
#define _CRT_SECURE_NO_WARNINGS//在vs2019编译器中输入scanf函数必须用到该行
#include<stdio.h>
#include"atm.h" //引用头文件
#define INITCAPACITY 10 //宏常量INITCAPACITY=10
void menu()//ATM主菜单界面
{
printf("***********欢迎进入ATM操作**************\n");
printf("********请选择你需要的功能操作:*********\n");
printf("**************1:登录*******************\n");
printf("**************2:注册*******************\n");
printf("**************3:退出*******************\n");
}
void show()
{
Array array;
int choice, id, password;//choice:输入的功能选择,id账户,password密码
init(&array, INITCAPACITY);
while (true) { //while循环可以多次选择功能而不是选择一次就退出了,终止条件是 3:退出
menu();
scanf("%d", &choice);
switch (choice)
{
case 1:
printf("请输入账号:\n");
scanf("%d", &id);
printf("请输入密码:\n");
scanf("%d", &password);
if(login_user(&array,id,password))
printf("登录成功");
else
printf("登录失败");
break;
case 2:
printf("请输入账号:\n");
scanf("%d", &id);
printf("请输入密码:\n");
scanf("%d", &password);
if (register_card(&array, id, password))
printf("注册成功");
else
printf("注册失败");
break;
case 3:
return;
break;
default:
break;
}
}
destory(&array); //释放malloc内存
}
int main()
{
show();
return 0;
}
运行结果:
1.测试操作:
2.测试登录函数
3.登陆成功继续操作,测试存款
4.登陆成功继续操作,测试取款
5.登陆成功继续操作,测试转账
检验如果余额大于本卡内余额是否提醒错误
再检验222卡内是否余额增加