/*******************************************
* 版权所有 (C)2015,Annpion。
*
* 文件名称:main.cpp
*文件标识:无
*内容摘要:该代码是程序的主要运行的首部分。
*其他说明:无
*当前版本:V1.0
*作者:王耀鹏
*完成日期:2015/7/17
*******************************************/
#include <iostream>
#include "Bank.h"
using namespace std;
int main()
{
cout<<"+-----------------------+\n";
cout<<"+ 欢迎光临中国银行 +\n";
cout<<"+-----------------------+\n";
if (pass())
{
Bank b;
b.work();
}
return 0;
}
/*******************************************
* 版权所有 (C)2015,Annpion。
*
* 文件名称:Bank.h
*文件标识:无
*内容摘要:该代码定义、声明类以及函数。
*其他说明:无
*当前版本:V1.0
*作者:王耀鹏
*完成日期:2015/7/17
*******************************************/
#ifndef BANK_H_INCLUDED
#define BANK_H_INCLUDED
#include <cstring>
using namespace std;
struct UserIndex
{
int No;
long offset;
};
class Bank;
class User
{
public:
void setUser(int acc, char *nam, int pw, double bal,int sta);
void showName();
void showStatus(string prompt);
int getaccount();
void showBalance(string prompt); //显示余额,前面加上提示词prompt
bool passwordIsRight(); //校验密码,输入的密码正确则返回true
bool isNormalUser(); //存款、取款、转帐等功能,需要账户处于正常姿态,处于正常状态时返回true,其他情形返回false并提示
friend class Bank;
private:
int account;
char name[8];
int password;
double balance;
int status;
};
class Bank
{
public:
Bank();
~Bank();
void work();
void openAccount();
void cancelAccount();
void save();
void withdraw();
void showAccount();
void transferAccounts();
void reportLoss();
void cancelLoss();
void updatePassword();
void createIndex();
void EnlargeArray();
void writeIndex(UserIndex *ui, int n);
long getUser();
private:
int maxNum;
int UserNum;
UserIndex *userIndex;
};
int pass();
int chooseInMenu();
int inputPassword();
void createIndex();
void writeIndex(UserIndex *ui, int n);
void init();
void done();
void EnlargeArray();
#endif // BANK_H_INCLUDED
/*******************************************
* 版权所有 (C)2015,Annpion。
*
* 文件名称:Bank.cpp
*文件标识:无
*内容摘要:该代码实现Bank类中的各个函数。
*其他说明:无
*当前版本:V1.0
*作者:王耀鹏
*完成日期:2015/7/17
*******************************************/
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <algorithm>
#include <ctype.h>
#include "bank.h"
using namespace std;
fstream dataFile, indexFile;
/*******************************************
*功能描述:构造Bank类中的数据成员。
*输入参数:User-用户类
*输出参数:userIndex-用户索引
UserNum-用户人数
*返回值:无
*其他说明:从文件中读入用户数据作成用户索引。
*******************************************/
Bank::Bank()
{
createIndex();
}
/*******************************************
*功能描述:析构Bank类。
*输入参数:无
*输出参数:无
*返回值:无
*其他说明:把索引写入文件,清除内存。
*******************************************/
Bank::~Bank()
{
writeIndex(userIndex,UserNum);
dataFile.close();
delete []userIndex;
}
/*******************************************
*功能描述:选择所需的功能。
*输入参数:iChoice-功能序号
*输出参数:无
*返回值:无
*其他说明:利用输入的序号调用各个功能函数。
*******************************************/
void Bank::work()
{
int iChoice;
do
{
iChoice = chooseInMenu();
switch(iChoice)
{
case 1:
openAccount(); //开户
break;
case 2:
cancelAccount(); //注销账户
break;
case 3:
save(); //存款
break;
case 4:
withdraw(); //取款
break;
case 5:
showAccount(); //查询余额
break;
case 6:
transferAccounts(); //转账
break;
case 7:
reportLoss(); //挂失
break;
case 8:
cancelLoss(); //解除挂失
break;
case 9:
updatePassword(); //更改密码
break;
case 0:
cout<<"欢迎您再来. "<<endl;
}
}
while(iChoice);
}
/*******************************************
*功能描述:开户。
*输入参数:user-用户类
*输出参数:userIndex-用户索引
UserNum-用户人数
*返回值:无
*其他说明:用户增加,索引增加,人数增加。
*******************************************/
void Bank::openAccount()
{
User user;
int acc; //账号
char nam[8]; //姓名
int pw; //密码
double bal; //金额
int sta;
cout<<"正在开户"<<endl;
acc=10001+UserNum;
cout<<"账号:"<<acc<<endl;
cout<<"户主姓名:";
cin>>nam;
int iPass1, iPass2;
cout<<"密码:";
iPass1=inputPassword(); //输入密码1
cout<<"确认密码:";
iPass2=inputPassword(); //输入密码2
if(iPass1==iPass2)
{
pw=iPass1;
sta=0; //账户状态为“正常”
cout<<"存入金额:";
cin>>bal;
user.setUser(acc, nam, pw, bal,sta);
dataFile.seekp(0,ios::end);
dataFile.write((char *)&user,sizeof(user));
dataFile.seekg(-sizeof(User),ios::end);
userIndex[UserNum].No=user.account;
userIndex[UserNum].offset=dataFile.tellg();
UserNum++; //正式用户数增加1,确认了新用户已经加入
cout<<"成功开户!"<<endl;
dataFile.seekp(0,ios::beg);
dataFile.write((char *)&UserNum,sizeof(UserNum));
if(UserNum>=maxNum)
EnlargeArray();
}
else
{
cout<<"两次密码不一致,未成功开户!"<<endl; //没有N++,则读入的值无效
}
}
/*******************************************
*功能描述:销户。
*输入参数:location-用户数据位置
*输出参数:user-用户类
*返回值:无
*其他说明:用户状态被改变。
*******************************************/
void Bank::cancelAccount()
{
User user;
long location;
location = getUser(); //根据账号查询用户,返回用户的偏移量
if(location>=0) //说明id账户存在
{
dataFile.seekg(location);
dataFile.read((char *)&user,sizeof(user));
user.showName();
if(user.isNormalUser())
{
if(user.passwordIsRight())
{
user.showBalance("余额"); //提示"余额"二字,显示金额
cout<<"确认销户(y/n)?";
if(tolower(getchar())=='y')
{
user.showBalance("销户成功!本次取款金额为");
user.balance=0; //取款后余额变0
user.status=2; //状态变为注销
dataFile.seekp(location);
dataFile.write((char *)&user,sizeof(user));
}
else
{
cout<<"你取消了操作,销户失败!"<<endl;
}
fflush(stdin); //清除了getchar()时在键盘缓存中的遗留,以免影响后续操作
}
}
}
}
/*******************************************
*功能描述:存款。
*输入参数:location-用户数据位置
*输出参数:user-用户类
*返回值:无
*其他说明:用户余额改变。
*******************************************/
void Bank::save()
{
User user;
long location;
double money;
location = getUser(); //根据账号查询用户,返回用户的偏移量
if(location>=0) //说明id账户存在
{
dataFile.seekg(location);
dataFile.read((char *)&user,sizeof(user));
user.showName();
if(user.isNormalUser())
{
cout<<"输入存款额:";
cin>>money;
user.balance+=money;
user.showBalance("存款后,您有");
dataFile.seekp(location);
dataFile.write((char *)&user,sizeof(User));
}
}
return;
}
/*******************************************
*功能描述:取款。
*输入参数:location-用户数据位置
*输出参数:user-用户类
*返回值:无
*其他说明:用户余额改变。
*******************************************/
void Bank::withdraw()
{
User user;
long location;
double money;
location = getUser(); //根据账号查询用户,返回用户的偏移量
if(location>=0) //说明id账户存在
{
dataFile.seekg(location);
dataFile.read((char *)&user,sizeof(User));
user.showName();
if(user.passwordIsRight())
{
if(user.isNormalUser())
{
cout<<"输入取款额:";
cin>>money;
if(money>user.balance) //亲,不玩透支
{
cout<<"余额不足,取款失败!"<<endl;
}
else
{
user.balance-=money;
user.showBalance("取款后,还有");
dataFile.seekp(location);
dataFile.write((char *)&user,sizeof(User));
}
}
}
}
return;
}
/*******************************************
*功能描述:查询。
*输入参数:location-用户数据位置
*输出参数:user-用户类
*返回值:无
*其他说明:显示用户数据。
*******************************************/
void Bank::showAccount()
{
User user;
long location;
location = getUser(); //根据账号查询用户,返回用户的偏移量
if(location>=0) //说明id账户存在
{
dataFile.seekg(location);
dataFile.read((char *)&user,sizeof(user));
user.showName();
if(user.passwordIsRight())
{
user.showBalance("余额:");
user.showStatus("状态:");
}
}
return;
}
/*******************************************
*功能描述:转账。
*输入参数:location-用户数据位置
*输出参数:user-用户类
*返回值:无
*其他说明:用户余额被改变。
*******************************************/
void Bank::transferAccounts()
{
User user1,user2;
long whoout, whoin;
double money;
cout<<"转出自";
whoout = getUser(); //根据账号查询用户,返回用户的偏移量
if(whoout>=0) //说明id账户存在
{
dataFile.seekg(whoout);
dataFile.read((char *)&user1,sizeof(User));
user1.showName();
if(user1.isNormalUser())
{
if(user1.passwordIsRight())
{
cout<<"输入转账金额:";
cin>>money;
if(money>user1.balance)
{
cout<<"余额不足,转账失败!"<<endl;
}
else
{
cout<<"转出到";
whoin = getUser(); //根据账号查询用户,返回用户的偏移量
if(whoin>=0) //说明id账户存在
{
dataFile.seekg(whoin);
dataFile.read((char *)&user2,sizeof(User));
if(user2.isNormalUser())
{
user1.balance-=money;
user2.balance+=money;
user1.showBalance("转账后,您还有");
dataFile.seekp(whoout);
dataFile.write((char *)&user1,sizeof(User));
dataFile.seekp(whoin);
dataFile.write((char *)&user2,sizeof(User));
}
}
}
}
}
}
return;
}
/*******************************************
*功能描述:挂失。
*输入参数:location-用户数据位置
*输出参数:user-用户类
*返回值:无
*其他说明:用户状态被改变。
*******************************************/
void Bank::reportLoss()
{
User user;
long location;
location = getUser(); //根据账号查询用户,返回用户的偏移量
if(location>=0) //说明id账户存在
{
dataFile.seekg(location);
dataFile.read((char *)&user,sizeof(User));
user.showName();
if(user.passwordIsRight())
{
if(user.isNormalUser())
{
user.status=1;
cout<<"挂失成功"<<endl;
dataFile.seekp(location);
dataFile.write((char *)&user,sizeof(user));
}
}
}
return;
}
/*******************************************
*功能描述:解挂。
*输入参数:location-用户数据位置
*输出参数:user-用户类
*返回值:无
*其他说明:用户状态被改变。
*******************************************/
void Bank::cancelLoss()
{
User user;
long location;
location = getUser(); //根据账号查询用户,返回用户的偏移量
if(location>=0) //说明id账户存在
{
dataFile.seekg(location);
dataFile.read((char *)&user,sizeof(User));
user.showName();
if(user.passwordIsRight())
{
if(user.status==0)
{
cout<<"该账户处于正常状态,不需要解除挂失"<<endl;
}
else if(user.status==1)
{
user.status=0;
cout<<"解除挂失成功"<<endl;
dataFile.seekp(location);
dataFile.write((char *)&user,sizeof(user));
}
else
{
cout<<"该账户已销户,操作无效"<<endl;
}
}
}
return;
}
/*******************************************
*功能描述:改密。
*输入参数:location-用户数据位置
*输出参数:user-用户类
*返回值:无
*其他说明:用户密码被改变。
*******************************************/
void Bank::updatePassword()
{
User user;
long location;
int iPass1,iPass2;
location = getUser(); //根据账号查询用户,返回用户的偏移量
if(location>=0) //说明id账户存在
{
if(user.isNormalUser())
{
dataFile.seekg(location);
dataFile.read((char *)&user,sizeof(User));
user.showName();
if(user.passwordIsRight())
{
cout<<"新密码:";
iPass1=inputPassword(); //输入密码1
cout<<"确认密码:";
iPass2=inputPassword(); //输入密码2
if(iPass1==iPass2)
{
user.password=iPass1;
cout<<"修改成功!"<<endl;
dataFile.seekp(location);
dataFile.write((char *)&user,sizeof(User));
}
else
{
cout<<"两次输入不同,修改失败!"<<endl;
}
}
}
}
return;
}
/*******************************************
*功能描述:建立索引。
*输入参数:user-用户类
*输出参数:userIndex-用户索引
*返回值:userIndex-用户索引
*其他说明:无。
*******************************************/
void Bank::createIndex()
{
User user;
dataFile.open("binarydata.dat",ios::out|ios::in|ios::binary);
if(!dataFile)
{
cerr<<"can't open binarydata.dat!"<<endl;
exit(1);
}
//建立索引
dataFile.read((char *)&UserNum,sizeof(UserNum));
maxNum=UserNum * 1.1;
userIndex=new UserIndex [maxNum];
//读入数据,建立未排序的索引表
int i, j;
long mOffset;
for(i=0; i<UserNum; ++i)
{
mOffset = dataFile.tellg();
dataFile.read((char*)&user, sizeof(user));
userIndex[i].No = user.getaccount();
userIndex[i].offset = mOffset;
}
UserIndex temp;
for (i=0; i<UserNum-1; i++)
for(j=0; j<UserNum-i-1; j++)
if (userIndex[j].No>userIndex[j+1].No)
{
temp=userIndex[j];
userIndex[j]=userIndex[j+1];
userIndex[j+1]=temp;
}
//将建好的索引表通过文件存储
writeIndex(userIndex, UserNum);
return ;
}
/*******************************************
*功能描述:扩大数组。
*输入参数:userIndex-用户索引
*输出参数:userIndex-用户索引
*返回值:无
*其他说明:扩大索引。
*******************************************/
void Bank::EnlargeArray()
{
User user;
maxNum = UserNum *1.1;
userIndex = new UserIndex[maxNum];
int i;
long mOffset;
for(i=0; i<UserNum; ++i)
{
mOffset = dataFile.tellg();
dataFile.read((char*)&user, sizeof(user));
userIndex[i].No = user.getaccount();
userIndex[i].offset = mOffset;
}
return ;
}
/*******************************************
*功能描述:写入索引。
*输入参数:userIndex-用户索引
*输出参数:userIndex.idx-索引文件名
*返回值:无
*其他说明:无。
*******************************************/
void Bank::writeIndex(UserIndex *ui, int n)
{
//打开文件
ofstream indexFile("userIndex.idx", ios::out|ios::binary);
if(!indexFile)
{
cerr<<"can't open userIndex.idx!"<<endl;
exit(1);
}
int i;
for(i=0; i<n; ++i)
{
indexFile.write((char*)&ui[i], sizeof(ui[i]));
}
//关闭文件
indexFile.close();
return;
}
/*******************************************
*功能描述:寻找用户位置。
*输入参数:id-用户账号
*输出参数:location-用户数据位置
*返回值:无
*其他说明:无。
*******************************************/
long Bank::getUser()
{
int id;
long location=-1;
int low=0,high=UserNum-1,mid;
cout<<"账号:";
cin>>id;
while(low<=high)
{
mid = (low+high)/2;
if(userIndex[mid].No==id)
{
location=userIndex[mid].offset;
break; //找到了,立即退出循环
}
else if (userIndex[mid].No>id)
high=mid-1;
else
low=mid+1;
}
if (location<0)
cout<<"该用户不存在,本次操作失败!"<<endl;
return location; //若找到,其值在0~N-1间,否则,保持-1
}
/*******************************************
* 版权所有 (C)2015,Annpion。
*
* 文件名称:User.cpp
*文件标识:无
*内容摘要:该代码实现User类中的各个函数。
*其他说明:无
*当前版本:V1.0
*作者:王耀鹏
*完成日期:2015/7/17
*******************************************/
#include <iostream>
#include "Bank.h"
using namespace std;
/*******************************************
*功能描述:设置User类中的数据成员。
*输入参数:acc-用户账号
nam-用户名称
pw-用户密码
bal-用户余额
sta-用户状态
*输出参数:user-用户类
*返回值:无
*其他说明:无。
*******************************************/
void User::setUser(int acc, char *nam, int pw, double bal,int sta)
{
account=acc;
password=pw;
strcpy(name,nam);
balance=bal;
status=sta;
}
/*******************************************
*功能描述:显示用户名称。
*输入参数:user-用户类
*输出参数:无
*返回值:无
*其他说明:显示姓名。
*******************************************/
void User::showName()
{
cout<<"户主姓名:"<<name<<endl;
}
void User::showStatus(string prompt)
{
cout<<prompt<<" ";
if(status==0)
cout<<"正常"<<endl;
else if(status==1)
cout<<"挂失"<<endl;
else cout<<"销户"<<endl;
}
/*******************************************
*功能描述:获取用户账号。
*输入参数:user-用户类
*输出参数:account-用户账号
*返回值:无
*其他说明:无。
*******************************************/
int User::getaccount()
{
return account;
}
/*******************************************
*功能描述:显示用户余额。
*输入参数:banlance-用户余额
prompt-显示语句
*输出参数:无
*返回值:无
*其他说明:无。
*******************************************/
void User::showBalance(string prompt)
{
cout<<prompt<<" "<<balance<<" 元"<<endl;
}
/*******************************************
*功能描述:核对用户密码。
*输入参数:password-用户密码
iPass-输入密码
*输出参数:right-判断对错
*返回值:true-正确,false-错误
*其他说明:无。
*******************************************/
bool User::passwordIsRight()
{
int iPass;
bool right = true;
cout<<"输入密码:";
iPass=inputPassword();
if(iPass!=password)
{
right = false;
cout<<"输入密码错误,不能继续操作!"<<endl;
}
return right;
}
/*******************************************
*功能描述:判断用户状态。
*输入参数:status-用户状态
*输出参数:normal-判断用户状态
*返回值:true-正常,false-异常
*其他说明:无。
*******************************************/
bool User::isNormalUser()
{
bool normal = true;
if(status!=0)
{
normal = false;
cout<<"该账户处于"<<(status==1?"挂失":"销户")<<"状态,不能继续操作..."<<endl;
}
return normal;
}
/*******************************************
* 版权所有 (C)2015,Annpion。
*
* 文件名称:Word.cpp
*文件标识:无
*内容摘要:该代码实现普通函数。
*其他说明:无
*当前版本:V1.0
*作者:王耀鹏
*完成日期:2015/7/17
*******************************************/
#include <iostream>
#include <fstream>
#include <conio.h>
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include "Bank.h"
using namespace std;
/*******************************************
*功能描述:验证业务员密码。
*输入参数:sNameInFile-业务员姓名
sPassInFile-业务员密码
sName-业务员输入姓名
sPass-业务员输入密码
*输出参数:right-判断正误
*返回值:1-成功,0-失败
*其他说明:无。
*******************************************/
int pass()
{
char sNameInFile[20]; //由文件中读出的业务员用户名
char sPassInFile[20]; //文件中保存的密码,这一版本中,用字符保存密码
ifstream infile("password.txt",ios::in);
if(!infile)
{
cout<<"password file cannot open!"<<endl;
exit(1);
}
infile>>sNameInFile>>sPassInFile;
infile.close();
char sName[20]; //业务员登录时输入的用户名
char sPass[20]; //业务员登录时输入的密码
char ch;
int iTry=3; //进入系统时尝试的次数
int right = 0; //要返回的结果:0-不正确 1-正确
//进入系统,密码三次不对将退出
do
{
cout<<"请输入业务员用户名:";
cin>>sName;
cout<<"请输入密码:";
int i=0;
while((ch=getch())!='\r') //getch在接受输入后,不在屏幕上显示
{
sPass[i++]=ch;
putchar('*'); //接受任何字符,屏幕上只显示*
}
sPass[i]='\0';
fflush(stdin);
cout<<endl;
if(strcmp(sPass,sPassInFile)==0&&strcmp(sName,sNameInFile)==0)
{
right = 1;
break;
}
else
{
iTry--;
if(iTry>0)
cout<<"超过3次将退出,你还可以尝试"<<iTry<<"次!"<<endl;
else
{
cout<<"对不起,你不能进入系统"<<endl;;
}
}
}
while(iTry);
return right;
}
/*
关于getch()的一点说明:
所在头文件:conio.h
函数用途:从控制台读取一个字符,但不显示在屏幕上
函数原型:int getch(void)
返回值:读取的字符
在不同平台,输入回车,getch()将返回不同数值,而getchar()统一返回10(即\n)
1)windows平台下ENTER键会产生两个转义字符 \r\n,因此getch返回13(\r)。
2)unix、 linux系统中ENTER键只产生 \n ,因此getch返回10(\n)。
3)MAC OS中ENTER键将产生 \r ,因此getch返回13(\r)。
为避免键盘缓存区中未读出的字符影响程序,用fflush(stdin);清除输入缓存区
*/
/*******************************************
*功能描述:选择功能。
*输入参数:i-功能序号
*输出参数:i-功能序号
*返回值:1-开户,2-销户,3-存款,4-取款,5-查询,6-转账,7-挂失,8-解挂,9-改密,0-退出
*其他说明:无。
*******************************************/
int chooseInMenu()
{
int i;
while(1)
{
cout<<endl;;
cout<<"+----------------------------+"<<endl;
cout<<"+ 1 开户 2 销户 3 存款 +"<<endl;
cout<<"+ 4 取款 5 查询 6 转账 +"<<endl;
cout<<"+ 7 挂失 8 解挂 9 改密 +"<<endl;
cout<<"+ 0 退出 +"<<endl;
cout<<"+----------------------------+"<<endl;
cout<<"请输入操作指令:";
cin>>i;
if(i>=0 && i<=9)
break;
else
cout<<"请重新选择功能"<<endl;;
}
return i;
}
/*
功能:输入密码
返回值:整型的密码值
技术说明:
(1)此功能在多个模块中都要用到且功能单一,故分离出来,单独作业一个函数
(2)为了便于在输入中只显示*,接受输入时以字符形式输入,而后转为对应的整型数
(3)规定密码由不全为0的6位数字构成(当开头是'0'时,实际不足6位),一旦输入错误将重新输入
附:在实际的系统中,密码通常用字符串描述,即使只允许出现数字字符,本例仅作为参考
*/
/*******************************************
*功能描述:输入密码。
*输入参数:iPass-用户密码
*输出参数:iPass-用户密码
*返回值:iPass-用户密码
*其他说明:输入的密码在显示时呈星号。
*******************************************/
int inputPassword()
{
char ch; //接收字符形式密码
int iPass=0; //要转换为数字
int i;
while(1)
{
for(i=0; i<6; i++)
{
ch=getch(); //输入但不显示
putchar('*'); //输出*
if(isdigit(ch))
iPass=iPass*10+(ch-'0');
else
{
iPass=0;
break; //退出for循环后,再次接受
}
}
fflush(stdin); //清除键盘缓存区中已经有的输入
cout<<endl;;
if(iPass==0) //此条件成立可能由两种情况引起:输入了非数字字符被直接重置为0,或6位全0后正常退出for循环
{
cout<<"密码要求全为数字,且不能全0!"<<endl;;
cout<<"请重新输入密码: ";
}
else
break;
}
return iPass;
}
运行结果: