登录时报错无法登陆(银行账户管理系统)(C++)
求看看如何修改
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
using namespace std;
class Account {
protected:
string name;//姓名
string id; //账号
string password;//密码
double balance;//余额
bool live; //账号是否存活
char mark; //标记是否为管理员
public:
Account() {}
Account(string nn, string ni, string np, double nb, bool nl, char nm) {
name = nn;
id = ni;
password = np;
balance = nb;
live = nl;
mark = nm;
}
//查询余额
double query() {
return balance;
}
//取款
bool withdraw(double money) {
if (balance < money)
return false;
balance -= money;
return true;
}
//存款
void deposit(double money) {
balance += money;
}
//成员对外接口
string getName() {
return name;
}
string getID() {
return id;
}
string getPassword() {
return password;
}
double getBalance() {
return balance;
}
char getMark() {
return mark;
}
bool isLive() {
return live;
}
void setPassword(string np) {
password = np;
}
void setLive(bool nl) {
live = nl;
}
void setBalance(double nb) {
balance = nb;
}
};
class FileTools {
public:
static vector<Account> accounts;
//读取文件中的账户信息
static void getAccounts() {
//打开文件读入流
ifstream in;
in.open("ID.txt", ios::in);
//读取数据到数组中
string id, password, name;
double balance;
char mark; //标记是否为管理员
accounts.clear();
while (in >> mark >> id >> password >> name >> balance) {
accounts.push_back(Account(name, id, password, balance, true, mark));
}
in.close();
}
//将内存中的账户信息存储到文件
static void saveAccounts() {
//打开文件输出流
ofstream out;
out.open("ID.txt", ios::out);
//输出到文件中(已经删除的账户就不存了)
for (int i = 0; i < accounts.size(); i++) {
Account a = accounts[i];
if (a.isLive())
out << a.getMark() << " " << a.getID() << " "
<< a.getPassword() << " " << a.getName() << " "
<< a.getBalance() << endl;
}
out.close();
}
//将日志信息写入到日志文件
static void addLog(string log) {
//打开文件输出流
ofstream out;
out.open("LOG.txt", ios::out|ios::app);
//输出到日志文件中
out <<log<< endl;
out.close();
}
//查找某个用户在数组中的位置
static int findAccountByID(string id) {
for (int i = 0; i < accounts.size(); i++) {
if (accounts[i].getID() == id) {
return 1;
}
}
//没找到返回-1;
return -1;
}
};
vector<Account> FileTools::accounts;
class Admin :public Account {
public:
Admin(Account a) {
name = a.getName();
id = a.getID();
password = a.getPassword();
balance = a.getBalance();
live = true;
}
//添加用户
void addAccount(Account a) {
FileTools::accounts.push_back(a);
}
//根据账号删除用户
bool deleteAccountByID(string id) {
int index = FileTools::findAccountByID(id);
//没找到账号
if (index == -1)
return false;
//修改账户为已死亡
FileTools::accounts[index].setLive(false);
return true;
}
//根据账号修改用户的余额
bool editPasswordByID(string id, string password) {
int index = FileTools::findAccountByID(id);
//没找到账号
if (index == -1)
return false;
//进行修改
FileTools::accounts[index].setPassword(password);
return true;
}
private:
};
class Frame {
int nowAccount; //当前用户(下标)
public:
Frame() {
int select;
while (true) {
//一级菜单
cout << "请输入选项进行对应操作" << endl;
cout << "1,用户登录" << endl;
cout << "2,管理员操作" << endl;
cout << "3,注册新用户" << endl;
cout << "0,退出" << endl;
cin >> select;
cout << "-------------------------------------------" << endl;
if (select == 0) {
//退出之前保存文件
FileTools::saveAccounts();
break;
}
string id, password;
int index;
switch (select) {
case 1: {
if (loginFrame()) {
accountFrame();
FileTools::saveAccounts();
}
break;
}
case 2: {
if (loginFrame()) {
if (FileTools::accounts[nowAccount].getMark() != '*') {
cout << "-------------------不是管理员-------------------" << endl;
}
else {
cout << "-------------------------------------------" << endl;
adminFrame();
FileTools::saveAccounts();
}
}
break;
}
case 3: {
registFrame();
break;
}
}
}
}
//登录窗口
bool loginFrame() {
string id, password;
int index;
cout << "输入账号密码" << endl;
while (true) {
cin >> id;
if (id == "0") { //登录失败
cout << "-------------------登录失败-------------------" << endl;
return false;
}
if ((index = FileTools::findAccountByID(id)) != -1) {
cin >> password;
if (password != FileTools::accounts[index].getPassword()) {
cout << "密码错误," << endl;
}
else {
//登录成功
cout << "-------------------登录成功-------------------" << endl;
nowAccount = index;
return true;
}
}
else {
//没找到账号
cout << "账号不存在,";
}
cout << "请重新输入账号密码或输入 0 退出" << endl;
}
}
//用户窗口
void accountFrame() {
int select;
double money;
while (true) {
cout << "1,存钱" << endl;
cout << "2,取钱" << endl;
cout << "3,查余额" << endl;
cout << "0,退出" << endl;
cin >> select;
if (select == 0)
return;
switch (select) {
case 1: {
cout << "输入金额:";
cin >> money;
double nowMoney = FileTools::accounts[nowAccount].getBalance();
FileTools::accounts[nowAccount].setBalance(nowMoney + money);
cout << "-------------------存钱成功-------------------" << endl;
break;
}
case 2: {
cout << "输入取钱金额:";
cin >> money;
double nowMoney = FileTools::accounts[nowAccount].getBalance();
if (nowMoney < money) {
cout << "-------------------余额不足-------------------" << endl;
}
else {
FileTools::accounts[nowAccount].setBalance(nowMoney - money);
cout << "-------------------取钱成功-------------------" << endl;
}
break;
}
case 3: {
cout << "当前余额为:" <<
FileTools::accounts[nowAccount].getBalance() << endl;
cout << "------------------------------------------" << endl;
break;
}
}
}
}
//管理员窗口
void adminFrame() {
int select;
string id, password, np, name;
Admin admin(FileTools::accounts[nowAccount]);
while (true) {
cout << "1,添加账户" << endl;
cout << "2,删除账户" << endl;
cout << "3,修改密码" << endl;
cout << "0,退出" << endl;
cin >> select;
if (select == 0)
break;
switch (select) {
case 1: {
cout << "输入账号,密码,姓名" << endl;
cin >> id >> password >> name;
admin.addAccount(Account(name, id, password, 0, true, '#'));
FileTools::saveAccounts();
cout << "-------------------添加成功-------------------" << endl;
break;
}
case 2: {
cout << "输入账号" << endl;
cin >> id;
if (admin.deleteAccountByID(id)) {
FileTools::saveAccounts();
cout << "-------------------删除成功-------------------" << endl;
}
else {
cout << "------------------账号不存在-------------------" << endl;
}
break;
}
case 3: {
cout << "输入账号,和新密码" << endl;
cin >> id >> np;
if (admin.editPasswordByID(id, np)) {
FileTools::saveAccounts();
cout << "-------------------账号重复-------------------" << endl;
}
else {
cout << "-------------------注册成功-------------------" << endl;
}
break;
}
}
}
}
//注册窗口
void registFrame() {
string name, id, password;
cout << "输入姓名" << endl;
cin >> name;
cout << "输入账号" << endl;
while (true) {
cin >> id;
if (FileTools::findAccountByID(id) != -1) {
//有重复的账号
cout << "-------------------账号重复-------------------" << endl;
}
else {
cout << "输入密码" << endl;
cin >> password;
FileTools::accounts.push_back(Account(name, id, password, 0, true, '#'));
FileTools::saveAccounts();
cout << "-------------------注册成功-------------------" << endl;
return;
}
}
}
};
int main() {
FileTools::getAccounts();
Frame frame;
return 0;
}
错误提示信息是vector下标越界
具体你不要直接运行,而是单步执行,这样可以告诉你出错的代码行。
从做完本次作业到写这篇博客已经过去了大概两三个月,对一些点可能已经忘记了。
中间也许有写的不好的地方,请大家见谅。
一、算法思想:
判断方法为使用DFS进行遍历,看是否可以将图节点全部遍历(判断是否是连通图),同时统计边数,判断是否为N-1。这两个条件缺一不可。即必须是连通图且边数为N-1(N为顶点个数)。
二、图的建立
首先一个比较困难的问题就是图的创建,我采用的是邻接表的形式创建的,有一个node1类型的数组ver,其用来存储节点的数据信息,每一个node1类型的struct都有一个data数据域和node2类型的指针域firstadj,用来指向其之后的节点信息。对于node2类型的struct,其也有两种类型的数据,一个是index,用来指示当前节点在之前数组的下标,还有一个就是nextadj,用来指向下一个以数组元素为箭头尾部的节点。具体如下边的代码。
同时还需要注意的一点就是,对于无向图的存储,我们使用邻接表存储的话,对其求边数,每个边数都统计了两遍的,最后得出的结果是要除以2才是真实的边数。
注释:由于我们使用的是邻接表存储图结构,每次输出拓扑排序的都是本邻接表所对应的拓扑排序。而图的邻接表可能有多种。对于求拓扑排序会有影响,但是对于我们的这次判断是否是树,邻接表只需要能表示出是哪个图就ok了。
struct node2 {
int index;//在数据数组中的下标,如果顶点编号从1开始,则index对应减1
node2* nextadj;//指向邻接表之后的节点
node2() {
index = -1;
nextadj = NULL;
}
};
struct node1 {
int data;//具体顶点值
node2* firstadj;//指向第一个节点
node1() {
firstadj = NULL;
data = -1;
}
};
对应到代码中就是我写的两个函数,一个创建顶点,一个创建边,大家仔细读一读就可以看懂,我就不过多叙述了。
void create_ver();//创建图顶点信息
void create_edge(int k, int length);//创建边信息
三、测试数据
1.第一个给出一个树来判断
判断结果如下:
2.再给出一个不是树的图
判断结果如下:
四、源代码
上述测试的两个图代码我都写在了下面。只需要将注释的改一改就可以了
#include<iostream>
#define v 6//V为定义的顶点数目
//#define v 7//V为定义的顶点数目
using namespace std;
struct node2 {
int index;//在数据数组中的下标,如果顶点编号从1开始,则index对应减1
node2* nextadj;//指向邻接表之后的节点
node2() {
index = -1;
nextadj = NULL;
}
};
struct node1 {
int data;//具体顶点值
node2* firstadj;//指向第一个节点
node1() {
firstadj = NULL;
data = -1;
}
};
//采用邻接表存储图
class Graph {
public:
Graph();
void create_ver();//创建图顶点信息
void create_edge(int k, int length);//创建边信息
void shuchu();//输出图的信息
bool istree();//判断是否是树,算法1
void DFS(int v0);//对图的遍历
private:
node1 ver[v];//存储顶点信息
bool visited[v];//存储是否访问过的信息
int count;//遍历时记录边的个数
};
//构造函数
Graph::Graph()
{
for (int i = 0; i < v; i++)//初始化数据数组
{
ver[i].data = -1;
ver[i].firstadj =NULL ;
}
for (int i = 0; i < v; i++)//初始化标志数组
visited[i] = false;
count = 0;
}
void Graph::DFS(int v0)
{
cout << ver[v0].data << " ";//访问第一个顶点
visited[v0] = true;//改变标志
node2* w = ver[v0].firstadj;//获得第一个邻接点
while (w!=NULL)//如果有的话,则进行下列判断
{
count++;//此处找到一条表
if (visited[w->index] != true)//如果没有访问过,则继续DFS
DFS(w->index);
w = w->nextadj;
}
}
bool Graph::istree()
{
cout << "深度优先遍历的顺序为:";
DFS(0);//遍历整个图
count = count / 2;//除以2为真实边数
cout<<endl << "该图的边数为:" << count << endl;
if (count != v - 1)//树的边数应该为N-1
return false;
for (int i = 0; i < v; i++) //即一次dfs没有访问完,此时应该为非连通图,故不是树
if (visited[i] == false)
return false;
}
void Graph::create_ver()
{
cout << "请依序输入图的顶点信息:";
for (int i = 0; i < v; i++)
{
int x;
cin >> x;
ver[i].data = x;
ver[i].firstadj = NULL;
}
}
//K为顶点编号,length为以该顶点为箭头尾部的边的条数
void Graph::create_edge(int k, int length)
{
cout << "*****************************************" << endl;
int x;//需要连接的节点编号
node2* p = NULL;
cout << "请输入顶点" << k << "的边信息:" << endl;
for (int i = 0; i < length; i++)
{
if (i == 0)
{
cout << "请输入第1条边(编号大于1):";
cin >> x;
ver[k - 1].firstadj = new node2;
ver[k - 1].firstadj->index = x - 1;
p = ver[k - 1].firstadj;//p指向新建立的节点
}
else
{
cout << "请输入第" << i + 1 << "条边:";
cin >> x;
p->nextadj = new node2;
p->nextadj->index = x - 1;
p = p->nextadj;//p指向新建的节点
}
}
cout << "*****************************************" << endl;
}
void Graph::shuchu()
{
cout << "*****************************************" << endl;
cout << "您所创建的图为:" << endl;
cout << "顶点为:" << endl;
for (int i = 0; i < v; i++)
cout << ver[i].data << " ";
cout << endl;
cout << "邻接链表结构为:" << endl;
for (int i = 0; i < v; i++)
{
cout << ver[i].data;
node2* p = ver[i].firstadj;
while (p != NULL)
{
cout << "→" << ver[p->index].data;
p = p->nextadj;
}
cout << endl;
}
cout << "*****************************************" << endl;
}
int main()
{
Graph G;
//创建图
G.create_ver();
/*//边数为7的数的创建
//create_edge的形参一为图顶点的编号,形参2为以该顶点为箭头尾部的边数
G.create_edge(1, 1);
G.create_edge(2, 2);
G.create_edge(3, 4);
G.create_edge(4, 1);
G.create_edge(5, 1);
G.create_edge(6, 1);
G.create_edge(7, 2);*/
//边数为6的创建
G.create_edge(1, 2);
G.create_edge(2, 3);
G.create_edge(3, 3);
G.create_edge(4, 3);
G.create_edge(5, 3);
G.create_edge(6, 2);
//判断是否是树
G.shuchu();
if (G.istree())
cout << "改图是树!!!";
else
cout << "该图不是树!!!";
return 0;
}