提高篇的最后一个程序-银行系统开发(四)

这是提高篇的最后一个程序,将会用到前面所讲的很多知识,同时很复杂,我跟着贺老师的代码自己做了一遍,这就是提升的过程!!

问题及代码:

/*
Copyright(c)2018,CSDN学院行者-
All rights reserved.
文件名称:main.c
作者:乔帅
完成日期:2018年4月6日
版本号:v1.0

问题描述:小小型应用系统开发指导(四)- 银行储蓄系统(四)
输入描述:帐号、密码等
程序操作:根据选的功能部分进行操作
程序输出:根据选择的功能操作后,输出操作后的结果
*/
/*
这将会是一个漫长的过程,也将是一个学习的过程,做下来就会有收获,加油!
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include<ctype.h>

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

int user[upNum][3];         //用与存放帐号、密码、帐号状态的二位数组
//用户状态0代表正常、1代表挂失、2代表销户
char name[upNum][10];       //用于存放用户名的二维数组
double balance[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);        //根据帐号找到用户数据所对应的下标

//以上为全局变量以及函数的声明

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

/*
功能:验证业务员密码
返回值:密码正确返回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 readDate()
{
    FILE *fp;           //用于文件操作
    int i = 0;
    if((fp = fopen("userDate.dat","r"))==NULL)          //这里使用dat文件保存数据
    {
        printf("user date file open error!\n");
        exit(0);
    }
    while(fscanf(fp,"%d %s %d %lf %d",&user[i][0],&name[i],&user[i][1],&balance[i],&user[i][2]) != EOF)
    {
        i++;
    }
    N = i;          //变量N保存实际用户数量
    fclose(fp);
    return;
}

/*
功能:将用户数据保存到文件中
*/
void writeDate()
{
    FILE *fp;
    int i;
    if((fp = fopen("userDate.dat","w"))==NULL)
    {
        printf("user date file open error!\n");
        exit(0);
    }
    for(i = 0 ; i < N ; i++)
    {
        fprintf(fp,"%d %s %d %lf %d\n",user[i][0],name[i],user[i][1],balance[i],user[i][2]);
    }
    fclose(fp);
    return;
}

/*
功能:办理业务
*/
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;
}

/*
功能:显示菜单并由业务员选择
返回值:用户选择的功能:范围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;
}

/*
功能:开户
说明:在进入系统时,读入数据的过程中,已经记录了实际用户数量为N,在数组中的范围0~N-1
      开户是要增加一个用户,并向数组下标为N的元素赋值,成功后同时N++
      但是顺序增加不方便后续的用户查找功能(只能使用顺序查找,这是不合算的)
      因此:开户时,根据帐号,将数据插入到数组的相应位置,使帐号有序排列,
      这样在search查找用户函数中就可以使用二分查找算法,大大加快查找速度
*/
void openAccount()
{
    int i, j;
    int temp;
    char ch;
    double d;
    if(upNum == N)
    {
        printf("银行用户数已达到上限,不能完成开户!\n");
        return;
    }
    printf("正在开户\n");
    printf("账号:");
    scanf("%d",&user[N][0]);
    printf("户主姓名:");
    scanf("%s",&name[N]);
    int iPass1,iPass2;
    printf("密码:");
    iPass1 = inputPassword();
    printf("确认密码:");
    iPass2 = inputPassword();
    if(iPass1 == iPass2)
    {
        user[N][1] = iPass1;
        user[N][2] = 0;     //账号状态正常
        printf("存入金额:");
        scanf("%lf",&balance[N]);
        N++;        //正式用户增加1
        printf("开户成功!\n");
        for(i = 0 ; i < N - 1 ; i++)
        {
            for(j = 0 ; j < N-i-1 ; j++)
            {
                if(user[j][0] > user[j+1][0])
                {
                    temp = user[j][0];          //账号互换
                    user[j][0] = user[j+1][0];
                    user[j+1][0] = temp;
                    temp = user[j][1];          //密码互换
                    user[j][1] = user[j+1][1];
                    user[j+1][1] = temp;
                    temp = user[j][2];          //状态互换
                    user[j][2] = user[j+1][2];
                    user[j+1][2] = temp;
                    ch = name[j][10];          //用户名互换
                    name[j][10] = name[j+1][10];
                    name[j+1][10] = ch;
                    d = balance[j];          //余额互换
                    balance[j] = balance[j+1];
                    balance[j+1] = d;
                }
            }
        }
    }
    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",name[who]);
        printf("密码:");
        iPass = inputPassword();
        if(iPass != user[who][1])
        {
            printf("密码输入错误,不能继续操作!\n");
        }
        else
        {
            printf("账户余额:%.2lf",balance[who]);
            printf("确认销户(Y/N):");
            if(tolower(getchar())=='y')
            {
                balance[who] = 0;       //销户后余额变为0
                user[who][2] = 2;       //状态变为销户
                printf("取款%.2lf元,销户成功!\n",balance[who]);
            }
            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][2]==0)
        {
            do
            {
                printf("户主姓名:%s\n",name[who]);
                printf("请输入存款金额:");
                scanf("%lf",&money);
                balance[who] += money;
                printf("存款成功!\n是否继续存款(Y/N):");
                fflush(stdin);
            }
            while(tolower(getchar())=='y');
        }
        else if(user[who][2] == 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][2] == 0)
        {
            printf("户主姓名:%s\n",name[who]);
            printf("请输入密码:");
            iPass = inputPassword();
            if(iPass != user[who][1])
            {
                printf("密码错误,取款失败!\n");
            }
            else
            {
                do
                {
                    printf("请输入取款金额:");
                    scanf("%lf",&money);
                    if(money>balance[who])
                    {
                        printf("余额不足,取款失败!\n");
                    }
                    else
                    {
                        balance[who] -= money;
                        printf("取款成功!账户余额为:%.2lf\n",balance[who]);
                        printf("是否继续取款(Y/N):");
                        fflush(stdin);
                    }
                }
                while(tolower(getchar())=='y');
            }
        }
        else if(user[who][2]==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",name[who]);
        printf("请输入密码:");
        iPass = inputPassword();
        if(iPass != user[who][1])
        {
            printf("密码错误,查询失败!\n");
        }
        else
        {
            printf("账户余额为:%.2lf\n",balance[who]);
            printf("状态:");
            if(user[who][2]==0)
            {
                printf("正常\n");
            }
            else if(user[who][2]==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",name[who]);
        printf("请输入密码:");
        iPass = inputPassword();
        if(iPass != user[who][1])
        {
            printf("密码错误,挂失失败!\n");
        }
        else
        {
            if(user[who][2] == 0)
            {
                user[who][2] = 1;       //挂失状态
                printf("挂失成功!\n");
            }
            else if(user[who][2]==1)
            {
                printf("该账户已处于挂失状态!\n");
            }
            else if(user[who][2]==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",name[who]);
        printf("请输入密码:");
        iPass = inputPassword();
        if(iPass != user[who][1])
        {
            printf("密码错误,解挂失败!\n");
        }
        else
        {
            if(user[who][2]==0)
            {
                printf("该账号处于正常状态,无需解挂!\n");
            }
            else if(user[who][2]==1)
            {
                user[who][2] = 0;
                printf("解除挂失成功!\n");
            }
            else if(user[who][2]==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][2]==0)
        {
            printf("转出户主姓名:%s",name[whoout]);
            printf("请输入密码:");
            iPass = inputPassword();
            if(iPass != user[whoout][1])
            {
                printf("密码错误,转账失败!\n");
            }
            else
            {
                printf("输入转账金额:");
                scanf("%lf",&money);
                if(money>balance[whoout])
                {
                    printf("余额不足,转账失败!\n");
                }
                else
                {
                    printf("输入转入账号:");
                    scanf("%d",&id);
                    whoin = search(id);
                    if(whoin<0)
                    {
                        printf("转入账号不存在,转账失败!\n");
                    }
                    else
                    {
                        if(user[whoin][2]>0)
                        {
                            printf("转入账号异常,转账失败!\n");
                        }
                        else
                        {
                            printf("转入户主姓名:%s\n",name[whoin]);
                            balance[whoout] -= money;
                            balance[whoin] += money;
                            printf("转账后您账户余额为:%.2lf\n",balance[whoout]);
                        }
                    }
                }
            }
        }
        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",name[who]);
        printf("请输入密码:");
        iPass = inputPassword();
        if(iPass != user[who][1])
        {
            printf("密码错误,不能继续操作!\n");
        }
        else
        {
            printf("新密码:");
            newPass = inputPassword();
            printf("确认密码:");
            rePass = inputPassword();
            if(newPass == rePass)
            {
                user[who][1] = newPass;
                printf("修改成功!\n");
            }
            else
            {
                printf("两次输入不同,修改失败!\n");
            }
        }
    }
    return;
}

/*
功能:输入密码
返回值:整形密码值
说明: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))
            {
                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;
}

/*
功能:根据帐号查询用户,并返回用户下标
入口参数:需要查询用户的帐号
返回值:如果该用户存在,返回该用户在数组中的下标,否则返回负数(-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][0])
        {
            index = mid;
            break;
        }
        else if(id<user[mid][0])
        {
            high = mid-1;
        }
        else
        {
            low = mid+1;
        }
    }
    return index;
}

运行结果:

由于篇幅问题这里不做过多演示。

知识点总结:

1.函数    2.二维数组    3.以及提高篇和初步篇的许多知识点

学习心得:

这个代码虽然很复杂,但他让我明白模块话程序设计的重要性,模块化程序设计可以使你的程序结构更加清晰,我们将会在写代码的过程中不断提升,一定要坚持。由于提高篇所学的知识有限,在学完进阶篇后我们将再次对银行储蓄系统进行优化处理,提高篇也在此告一段落,让我们在进阶篇里不见不散!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值