第21章项目-银行储蓄系统(第五版)开发

本项目将第四版银行储蓄系统中数组存储用户信息的方式替换为结构体,旨在提高代码灵活性。后续计划进一步优化,将用户数据存储改为链表形式,尽管这可能导致顺序查找效率降低,但旨在提升链表操作的熟练度。
摘要由CSDN通过智能技术生成
问题及问题代码:

将前面的第四版银行储蓄系统(第四版)开发,中用数组存储用户信息,改为使用结构体来存储

实例代码:
总览:

main.c
#include <stdio.h>
#include "bank.h"

/*主函数*/
int main()
{
    printf("+-------------------------------------+\n");
    printf("+           欢迎光临乔氏银行          +\n");
    printf("+-------------------------------------+\n");
    if(pass())
    {
        readDate();         //读入数据
        work();             //业务驱动
        writeDate();        //写入数据
    }
    return 0;
}
bank.h
#ifndef BANK_H_INCLUDED
#define BANK_H_INCLUDED

#define upNum 2000          //系统可容纳最大客户数量

struct data{
    int account;            //账号
    int Password;           //密码
    char name[10];          //用户名
    double balance;         //账户余额
    int status;             //状态
};

struct data user[upNum];

int N;          //实际用户数量

int pass();         //业务员帐号登录
void readDate();    //读入数据
void writeDate();   //写入数据
void work();        //业务驱动
int chooseInMenu();    //选择菜单,并由业务员进行选择
void showAccount();     //查询余额
void openAccount();     //开户
void cancelAccount();   //销户
void reportLoss();      //挂失
void cancelLoss();      //解挂
void save();            //存款
void withdraw();        //取款
void transferAccounts();    //转账
void updatePasswork();  //改密码
int inputPassword();    //输入密码并做加密处理,同时返回密码值
int search(int);        //根据帐号找到用户数据所对应的下标

//以上为全局变量以及函数的声明
#endif // BANK_H_INCLUDED
bank.c
#include<stdio.h>
#include<ctype.h>

#include "bank.h"

/*
功能:开户
说明:在进入系统时,读入数据的过程中,已经记录了实际用户数量为N,在数组中的范围0~N-1
      开户是要增加一个用户,并向数组下标为N的元素赋值,成功后同时N++
      但是顺序增加不方便后续的用户查找功能(只能使用顺序查找,这是不合算的)
      因此:开户时,根据帐号,将数据插入到数组的相应位置,使帐号有序排列,
      这样在search查找用户函数中就可以使用二分查找算法,大大加快查找速度
*/
void openAccount()
{
    int i, j;
    struct data temp;
    if(upNum == N)
    {
        printf("银行用户数已达到上限,不能完成开户!\n");
        return;
    }
    printf("正在开户\n");
    printf("账号:");
    scanf("%d",&user[N].account);
    printf("户主姓名:");
    scanf("%s",&user[N].name);
    int iPass1,iPass2;
    printf("密码:");
    iPass1 = inputPassword();
    printf("确认密码:");
    iPass2 = inputPassword();
    if(iPass1 == iPass2)
    {
        user[N].Password = iPass1;
        user[N].status = 0;     //账号状态正常
        printf("存入金额:");
        scanf("%lf",&user[N].balance);
        N++;        //正式用户增加1
        printf("开户成功!\n");
        for(i = 0 ; i < N - 1 ; i++)
        {
            for(j = 0 ; j < N-i-1 ; j++)
            {
                if(user[j].account > user[j+1].account)
                {
                    temp = user[j];
                    user[j] = user[j+1];
                    user[j+1] = user[j];
                }
            }
        }
    }
    else
    {
        printf("两次密码不一致,开户失败!\n");
    }
    return;
}
/*
功能:注销账户
说明:找到账户信息,将状态改为2-注销即可
    注销前应注意账户余额,如有存款,应先取款在注销
*/
void cancelAccount()
{
    int id;         //用于输入账号
    int who;        //查找该账号所对应数组下标
    int iPass;
    printf("待销户账号:");
    scanf("%d",&id);
    who = search(id);   //根据账号查询用户,返回用户下标
    if(who<0)           //说明id用户不存在
    {
        printf("该用户不存在,销户失败!\n");
    }
    else
    {
        printf("户主姓名:%s\n",user[who].name);
        printf("密码:");
        iPass = inputPassword();
        if(iPass != user[who].Password)
        {
            printf("密码输入错误,不能继续操作!\n");
        }
        else
        {
            printf("账户余额:%.2lf",user[who].balance);
            printf("确认销户(Y/N):");
            if(tolower(getchar())=='y')
            {
                user[who].balance = 0;       //销户后余额变为0
                user[who].status = 2;       //状态变为销户
                printf("取款成功,余款%.2lf元.\n",user[who].balance);
                printf("销户成功!\n");
            }
            else
            {
                printf("您取消操作,销户失败!\n");
            }
        }
    }
    return;
}
/*
功能:存款
说明:存款账户必须存在,同时账户需处在正常状态方能存款
*/
void save()
{
    int id,who;
    double money;
    printf("请输入存款账号:");
    scanf("%d",&id);
    who = search(id);
    if(who < 0)
    {
        printf("该用户不存在,存款失败!\n");
    }
    else
    {
        if(user[who].status==0)
        {
            do
            {
                printf("户主姓名:%s\n",user[who].name);
                printf("请输入存款金额:");
                scanf("%lf",&money);
                user[who].balance += money;
                printf("存款成功!\n是否继续存款(Y/N):");
                fflush(stdin);
            }
            while(tolower(getchar())=='y');
        }
        else if(user[who].status == 1)
        {
            printf("该用户处于挂失状态,存款失败!\n");
        }
        else
        {
            printf("该用户已经销户,存款失败!\n");
        }
    }
    return;
}
/*
功能:取款
说明:取款账户必须存在,同时账户需处在正常状态方能取款
      账户余额应大于取款金额,否则不能取款
*/
void withdraw()
{
    int id,who,iPass;
    double money;
    printf("请输入取款账号:");
    scanf("%d",&id);
    who = search(id);
    if(who<0)
    {
        printf("该用户不存在,取款失败!\n");
    }
    else
    {
        if(user[who].status == 0)
        {
            printf("户主姓名:%s\n",user[who].name);
            printf("请输入密码:");
            iPass = inputPassword();
            if(iPass != user[who].Password)
            {
                printf("密码错误,取款失败!\n");
            }
            else
            {
                do
                {
                    printf("请输入取款金额:");
                    scanf("%lf",&money);
                    if(money>user[who].balance)
                    {
                        printf("余额不足,取款失败!\n");
                    }
                    else
                    {
                        user[who].balance -= money;
                        printf("取款成功!账户余额为:%.2lf\n",user[who].balance);
                        printf("是否继续取款(Y/N):");
                        fflush(stdin);
                    }
                }
                while(tolower(getchar())=='y');
            }
        }
        else if(user[who].status==1)
        {
            printf("该用户处于挂失阶段,取款失败!\n");
        }
        else
        {
            printf("该用户已注销,取款失败!\n");
        }
    }
    return;
}
/*
功能:查询余额
说明:显示账户信息
*/
void showAccount()
{
    int id,who,iPass;
    printf("请输入待查询的账号:");
    scanf("%d",&id);
    who = search(id);
    if(who<0)
    {
        printf("该用户不存在,查询失败!\n");
    }
    else
    {
        printf("户主姓名:%s\n",user[who].name);
        printf("请输入密码:");
        iPass = inputPassword();
        if(iPass != user[who].Password)
        {
            printf("密码错误,查询失败!\n");
        }
        else
        {
            printf("账户余额为:%.2lf\n",user[who].balance);
            printf("状态:");
            if(user[who].status==0)
            {
                printf("正常\n");
            }
            else if(user[who].status==1)
            {
                printf("挂失\n");
            }
            else
            {
                printf("已经销户\n");
            }
        }
    }
    return;
}
/*
功能:挂失账户
说明:需要验证用户身份信息
*/
void reportLoss()
{
    int id,who,iPass;
    printf("请输入需要挂失的账号:");
    scanf("%d",&id);
    who = search(id);
    if(who<0)
    {
        printf("该账户不存在,挂失失败!\n");
    }
    else
    {
        printf("户主姓名:%s\n",user[who].name);
        printf("请输入密码:");
        iPass = inputPassword();
        if(iPass != user[who].Password)
        {
            printf("密码错误,挂失失败!\n");
        }
        else
        {
            if(user[who].status == 0)
            {
                user[who].status = 1;       //挂失状态
                printf("挂失成功!\n");
            }
            else if(user[who].status==1)
            {
                printf("该账户已处于挂失状态!\n");
            }
            else if(user[who].status==2)
            {
                printf("该账户已注销,不能挂失!\n");
            }
        }
    }
    return;
}
/*
功能:解除挂失
说明:帐号要处于挂失状态,同时需要验证身份信息
*/
void cancelLoss()
{
    int id,who,iPass;
    printf("请输入待解挂的账号:");
    scanf("%d",&id);
    who = search(id);
    if(who<0)
    {
        printf("该账户不存在,解挂失败!\n");
    }
    else
    {
        printf("户主姓名:%s\n",user[who].name);
        printf("请输入密码:");
        iPass = inputPassword();
        if(iPass != user[who].Password)
        {
            printf("密码错误,解挂失败!\n");
        }
        else
        {
            if(user[who].status==0)
            {
                printf("该账号处于正常状态,无需解挂!\n");
            }
            else if(user[who].status==1)
            {
                user[who].status = 0;
                printf("解除挂失成功!\n");
            }
            else if(user[who].status==2)
            {
                printf("该账号已销户,解挂失败!\n");
            }
        }
    }
    return;
}
/*
功能:转账
说明:要保证两个用户都存在并处于正常状态,并且转出账户余额应大于转出额,才能转账
*/
void transferAccounts()
{
    int id,whoout,whoin;
    int iPass;
    double money;
    printf("请输入转出账号:");
    scanf("%d",&id);
    whoout = search(id);
    if(whoout < 0)
    {
        printf("该用户不存在,转账失败!\n");
    }
    else
    {
        if(user[whoout].status==0)
        {
            printf("转出户主姓名:%s",user[whoout].name);
            printf("请输入密码:");
            iPass = inputPassword();
            if(iPass != user[whoout].Password)
            {
                printf("密码错误,转账失败!\n");
            }
            else
            {
                printf("输入转账金额:");
                scanf("%lf",&money);
                if(money>user[whoout].balance)
                {
                    printf("余额不足,转账失败!\n");
                }
                else
                {
                    printf("输入转入账号:");
                    scanf("%d",&id);
                    whoin = search(id);
                    if(whoin<0)
                    {
                        printf("转入账号不存在,转账失败!\n");
                    }
                    else
                    {
                        if(user[whoin].status>0)
                        {
                            printf("转入账号异常,转账失败!\n");
                        }
                        else
                        {
                            printf("转入户主姓名:%s\n",user[whoin].name);
                            user[whoout].balance -= money;
                            user[whoin].balance += money;
                            printf("转账后您账户余额为:%.2lf\n",user[whoout].balance);
                        }
                    }
                }
            }
        }
        else
        {
            printf("该账户异常,转账失败!\n");
        }
    }
    return;
}
/*
功能:修改密码
*/
void updatePasswork()
{
    int id,who;
    int iPass,newPass,rePass;
    printf("请输入账号:");
    scanf("%d",&id);
    who = search(id);
    if(who<0)
    {
        printf("该账号不存在,修改密码失败!\n");
    }
    else
    {
        printf("户主姓名:%s",user[who].name);
        printf("请输入密码:");
        iPass = inputPassword();
        if(iPass != user[who].Password)
        {
            printf("密码错误,不能继续操作!\n");
        }
        else
        {
            printf("新密码:");
            newPass = inputPassword();
            printf("确认密码:");
            rePass = inputPassword();
            if(newPass == rePass)
            {
                user[who].Password = newPass;
                printf("修改成功!\n");
            }
            else
            {
                printf("两次输入不同,修改失败!\n");
            }
        }
    }
    return;
}
/*
功能:根据帐号查询用户,并返回用户下标
入口参数:需要查询用户的帐号
返回值:如果该用户存在,返回该用户在数组中的下标,否则返回负数(-1)
说明:由于前面开户模块已将用户按顺序排列,所以该模块可以使用二分查找而加快查找速度
*/
int search(int id)
{
    int index = -1;
    int low = 0, high = N-1;
    int mid;
    while(low<=high)
    {
        mid = (low + high)/2;
        if(id == user[mid].account)
        {
            index = mid;
            break;
        }
        else if(id<user[mid].account)
        {
            high = mid-1;
        }
        else
        {
            low = mid+1;
        }
    }
    return index;
}
work.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include<ctype.h>

#include "bank.h"

/*
功能:验证业务员密码
返回值:密码正确返回1
        不能通过密码验证,即密码错误返回0
*/
/*
关于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);清除输入缓存区
*/
int pass()
{
    char nameInfile[20];        //读取文件中的用户名
    char passwordInfile[20];      //读取相应用户的密码
    char name[20];           //从键盘输入的用户名
    char password[20];       //从键盘输入的密码
    char ch;
    int right = 0;                      //返回验证信息,用户名密码正确,返回1,否则返回0
    int iTry = 3;       //可验证次数
    FILE *fp;
    //从密码文件中取出数据
    if((fp = fopen("worker.txt","r")) == NULL)
    {
        printf("password file open error!");
        exit(0);
    }
    fscanf(fp, "%s %s", nameInfile,passwordInfile);
    fclose(fp);
    //进入系统,密码三次不对将退出
    do
    {
        printf("请输入业务员用户名:");
        scanf("%s",name);
        printf("请输入密码:");
        int i = 0;
        while((ch = getch())!='\r')         //getch接受输入后不显示
        {
            password[i++] = ch;
            putchar('*');       //接受任何字符,屏幕上只显示*
        }
        password[i] = '\0';
        fflush(stdin);
        printf("\n");
        if(strcmp(name,nameInfile)==0&&strcmp(password,passwordInfile)==0)
        {
            right = 1;
            break;
        }
        else
        {
            iTry--;
            if(iTry > 0)
            {
                printf("超过三次将退出,您还可以尝试%d次\n",iTry);
            }
            else
            {
                printf("对不起,您不能进入系统!\n");
            }
        }
    }
    while(iTry > 0);
    return right;
}

/*
功能:办理业务
*/
void work()
{
    int ichoose;
    do
    {
        ichoose = chooseInMenu();
        switch(ichoose)
        {
        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:
            updatePasswork();
            break;
        case 0:
            printf("欢迎您下次光临!\n");
        }
    }
    while(ichoose);
    return;
}
/*
功能:从文件中读取储户数据
*/
/*
功能:从文件中读入用户数据
*/
void readDate()
{
    FILE *fp;           //用于文件操作
    int i = 0;
    if((fp = fopen("userData.dat","r"))==NULL)          //这里使用dat文件保存数据
    {
        printf("user date file open error!\n");
        exit(0);
    }
    while(fscanf(fp,"%d %s %d %lf %d",&user[i].account,&user[i].name,&user[i].Password,&user[i].balance,&user[i].status) != EOF)
    {
        i++;
    }
    N = i;          //变量N保存实际用户数量
    fclose(fp);
    return;
}
/*
功能:将用户数据保存到文件中
*/
void writeDate()
{
    FILE *fp;
    int i;
    if((fp = fopen("userData.dat","w"))==NULL)
    {
        printf("user data file open error!\n");
        exit(0);
    }
    for(i = 0 ; i < N ; i++)
    {
        fprintf(fp,"%d %s %d %lf %d\n",user[i].account,user[i].name,user[i].Password,user[i].balance,user[i].status);
    }
    fclose(fp);
    return;
}
/*
功能:显示菜单并由业务员选择
返回值:用户选择的功能:范围0-9之间
*/
int chooseInMenu()
{
    int Menu;
    while(1)            //选择错误可以重新选择
    {
        printf("+------------------------------------+\n");
        printf("+ 1.开户    2.销户        3.存款     +\n");
        printf("+ 4.取款    5.查询余额    6.转账     +\n");
        printf("+ 7.挂失    8.解挂        9.修改密码 +\n");
        printf("+ 0.退出系统                         +\n");
        printf("+------------------------------------+\n");
        printf("请输入操作指令:");
        scanf("%d",&Menu);
        if(Menu>=0&&Menu<=9)        //保证选择的指令符合
        {
            break;
        }
        else
        {
            printf("请重新选择功能!\n");
        }
    }
    return Menu;
}
/*
功能:输入密码
返回值:整形密码值
说明:1.该函数在每一模块均要使用,同时功能单一,故分离出来单独做一个函数来实现
      2.为方便进行显示加密处理,故输入时以字符的形式输入,后转换为对应整数并返回
      3.规定密码由不全为0的6位数字构成(当开头是'0'时,实际不足6位),一旦输入错误将重新输入
*/
int inputPassword()
{
    char password;      //接受字符形式密码
    int iPass = 0;      //转换后的数字密码
    int i;
    while(1)
    {
        for(i = 0 ; i < 6 ; i++)
        {
            password = getch();
            putchar('*');
            if(isdigit(password))           //isdigit检测传入的是否为十进制数
            {
                iPass = iPass*10+(password-'0');        //iPass
            }
            else
            {
                iPass = 0;
                break;
            }
        }
        fflush(stdin);
        printf("\n");
        if(iPass == 0)              //两种情况,1.输入全为0正常退出  2.输入了非数字字符被重置为0
        {
            printf("密码要求为全数字,切不能全为0\n");
            printf("请重新输入密码:");
        }
        else
        {
            break;
        }
    }
    return iPass;
}
总结:

后期还会将用户储存改为使用链表的形式进行存储,但单链表储存在查找数据时,只能使用顺序查找,这样会导致效率低下,当做一次练习来做,更加熟悉链表的使用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值