• / 33
  • 下载费用:12 金币  

C语言如何模拟ATM机的资料.doc

关 键 词:
语言 如何 模拟 ATM 资料
资源描述:
\\一、 实验目的通过设计一个ATM机模拟操作的程序,全面运用课程的主要知识点,巩固对模块化程序设计、文件操作的理解,提高软件编程能力。二、 实验要求要求每人独立完成设计,编写一个ATM机模拟操作程序。提交实验报告、源程序、程序运行截图。1. 程序具有以下功能:1) 登录系统:输入卡号(16位)、密码(6位),只有卡号、密码同时正确(帐户信息存放在文件中)才能进入系统;2) 操作功能:l 查询:查询帐户的存款余额。按任意键返回主菜单;l 修改密码:连续输入两次新密码(两次输入结果完全相同)后,新密码取代旧密码,并存放到帐户信息文件中。之后可返回主菜单;l 取款:输入50或100的倍数模拟为取款金额,请注意:取款金额不得超过帐户余额,操作后帐户余额应相应减少。之后可返回主菜单;l 存款:输入50或100的倍数模拟为存款金额,现假设存款金额不得超过20000元,操作后帐户余额应相应增加。之后可返回主菜单;l 转帐:先输入一个帐户号(已保存在帐户信息文件中),然后显示一部分用户名(如:张*山),储户确认无误后,再输入50或100的倍数模拟为转帐金额,请注意:转帐金额不得超过帐户余额,操作后帐户余额应相应减少。之后可返回主菜单;l 退出:退出系统。2. 定义如下结构体类型:l “日期”结构体Date:成员有:year(年)、month(月)、day(日);l “帐户”结构体Account:成员有:no(帐户号)、name(姓名)、balance(余额)l “存取款记录”结构体Record,:成员有:no(帐户号)、date(日期)、number(数量,可正可负,正表示存款,负表示取款)3. 帐户信息存放在accounts.txt文件,储户存取款记录保存在records.txt中;4. 采用模块化程序设计方法来实现,即main()显示主菜单、调用相关函数实现相应功能,起主控作用。5. 附加功能:l 储户一天内输错密码的次数不能超过3次,否则无法进入系统;l 应避免输入存款金额、取款金额为负数等异常情况的出现。三、 程序已经实现的功能点实验要求均已实现。此外还有:1. 卡号、密码位数输错时,提示并返回重新输入,2. 简化取款时的输入3. 转账时,转账账户为原账户时,提示并返回重新输入4. 在多个模块中添加了退出功能,无需回到主菜单即可退出系统5. 在查询模块中加入了存取记录明细查询四、 程序运行截图及说明1. 登陆模块1) 卡号不为16位时,输出提示并返回重新输入2) 卡号不存在时,输出提示并返回重新输入3) 密码位数输错时,输出提示并返回重新输入密码,不作为密码错误处理,也无需重新输入卡号4) 密码连续输错三次时,锁定卡号,今日无法登录2. 登录后的系统主菜单3. 查询模块1) 查询模块主菜单2) 查询明细4. 取款模块1) 当余额不足50时,无法进入取款模块2) 取款模块主菜单3) 便捷取款4) 手动输入取款金额输错时,返回重新输入5) 取款后的菜单6) 取款完成后选择显示余额5. 存款模块1) 解决输入错误问题2) 存款成功6. 密码修改模块1) 原密码输错时,返回重新输入,不提供退出功能2) 密码位数输错、两次输入新密码不一致时,返回重新输入3) 输入无误时7. 转账模块1) 转入卡号位数输错时,提示并返回重新输入2) 未查找到该卡号时,输出提示,提供退出功能,键入除*外任意键重新输入3) 转入卡号与当前卡号相同时,输出提示4) 输出转入卡账户的部分用户名5) 解决转账金额输错的问题6) 转账成功五、 采用的主要技术1. 宏定义:由于本程序的printf语句较多,为了便于编写,故用PR代替2. 链表:账户信息采用链表结构,内存动态分配,使用内存无限制,可以扩展到所有可以使用的内存3. switch多分支选择结构4. 文本文件的读写5. 利用time.h头文件,简便地获取系统日期6. system()函数和fflush()函数的简单使用六、 设计心得1. 各函数的功能要相对独立,逐步求精。2. 如果函数的参数为指针,且仅作为输入参数,则应在类型前加const,以防止该指针在函数体内被意外修改附:程序代码/****运行本程序前,请在本程序根目录下建立文件“accounts.txt”,格式如下:*卡号1(16位)姓名1账户余额1密码1*卡号2(16位)姓名2账户余额2密码2*……****/#include #include #include #include #define PR printftypedef struct{short int year;short int month;short int day;}Date;//日期typedef struct Account{char no[17];char name[20];double balance;char password[7];struct Account* next;}Account;typedef struct{char no[17];Date date;double number;}Record;//记录Account *head = NULL;//账户信息链表表头Account *now_acc = NULL;//当前账户 /************函数申明************/void InitializeAccount();//导入账户信息//--------------------------------------char LockAccountTopic(const char *no);//检测账户是否被锁定void LockAccount(const char *no);//锁定账户//--------------------------------------void Login();//登录Account* FindbyNo(const char *no);//查找卡号对应账户信息在链表中的地址//--------------------------------------void Demand();//查询主菜单void PrintBalance();//输出余额void Printetail();//输出明细//--------------------------------------void Modifiy();//修改密码//--------------------------------------void Withdrawal();//取款主界面void WithdrawalOt(long money);//取款//--------------------------------------void Depositing();//存款//--------------------------------------void Transfer();//转账char *CoverUpName(const char *name);//掩盖部分用户名//--------------------------------------void Log(double money, const char *no);//将存款记录写入文件中void Save();//保存账号信息void FreeData();//释放链表空间//--------------------------------------int main(){char choose;InitializeAccount();//导入账户信息Login();//登录do{system("cls");PR("\t\t \n");PR("\t\t 请选择服务 \n");PR("\t\t+-+---------+ +---------+-+\n");PR("\t\t|5|\33转 账| |查 询\32|1|\n");PR("\t\t+-+---------+ +---------+-+\n\n");PR("\t\t +---------+-+\n");PR("\t\t |取 款\32|2|\n");PR("\t\t +---------+-+\n\n");PR("\t\t +---------+-+\n");PR("\t\t |存 款\32|3|\n");PR("\t\t +---------+-+\n\n");PR("\t\t+-+---------+ +---------+-+\n");PR("\t\t|0|\33退出系统| |修改密码\32|4|\n");PR("\t\t+-+---------+ +---------+-+\n\n");PR("请选择服务:");fflush(stdin);choose = getchar();switch (choose){case '1': Demand(); break;//查询case '2': Withdrawal(); break;//取款case '3': Depositing(); break;//存款case '4': Modifiy(); break;//修改密码case '5': Transfer(); break;//转账case '0': FreeData(); return 0;//退出default:printf("输入错误,请重新选择\n"); //解决用户可能的输入错误system("pause");}} while (1);return 0;}/**********导入账户信息**********/void InitializeAccount(){FILE *fp;Account temp;PR("系统初始化中,请稍侯...\n");if (!(fp = fopen("accounts.txt", "r"))){PR("\07");//响铃PR("读取帐户信息失败,请在本程序根目录建立帐户信息文件(accounts.txt)。格式如下:\n");PR("卡号1(16位)姓名1账户余额1密码1\n");PR("卡号2(16位)姓名2账户余额2密码2\n");PR("……\n");exit(0);}while (fscanf(fp, "%s %s %lf %s", temp.no, temp.name, &temp.balance, temp.password) == 4){//读入账户信息Account *t = head;head = (Account*)malloc(sizeof(Account));*head = temp;head->next = t;}fclose(fp);system("cls");//清除“系统初始化中,请稍侯...”提示}/**********登录**********/void Login(){do{char no[17];system("cls");PR("\n\n\n\n\t\t\t请输入16位卡号:");fflush(stdin);gets(no);if (strlen(no) != 16){PR("卡号应为16位\n");system("pause");system("cls");continue;}if (LockAccountTopic(no)){//当该卡号被锁定时PR("\07");//响铃PR("\n\n您的登陆密码今日连续输错三次,已被临时锁定,次日将自动解锁,或当日持本人有效证件到柜台办理密码重置。\n\n");system("pause");continue;}if (!(now_acc = FindbyNo(no)))//将卡号对应信息在链表的地址赋给now_acc{//当卡号不存在时PR("\n\n此卡号不存在,请重新输入!\n\n");system("pause");continue;}char a = '2';//计算剩余可输错密码次数do{char password[7];system("cls");PR("\n\n\n\n\t\t\t请输入16位卡号:%s\n", now_acc->no);PR("\n\n\t\t\t请输入6位密码:");fflush(stdin);scanf("%s", password);if (strlen(password) != 6){PR("密码应为6位\n");system("pause");system("cls");continue;}if (!strcmp(now_acc->password, password))return;//密码正确,回到主函数if (a == '0'){//输错密码三次,锁定账户PR("\n\n您的登陆密码今日连续输错三次,已被临时锁定,次日将自动解锁,或当日持本人有效证件到柜台办理密码重置。\n\n");LockAccount(no);break;}PR("\07");//响铃PR("密码输入错误,您还可以尝试%c次\n\n", a--);system("pause");} while (1);} while (1);}/**********检测账户是否被锁定**********/char LockAccountTopic(const char *no)//被锁定则返回0{FILE *fp;char CruuentTime[11];//当前日期char ArchiveTime[11];//锁卡档案日期char t[17];if (!(fp = fopen("LockAccount.txt", "a+")))//课本上讲以“a”方式打开文件,若文件不存在,会出错。VS2013实测,并不会出错,而是新建。为免第一次使用本程序时,根目录下没有LockAccount.txt而导致出错,故此处不采用“r”方式。{PR("\07");//响铃PR("LockAccount.txt无法打开\n\n");exit(0);}rewind(fp);{//获取当前日期time_t rawtime;struct tm * timeinfo;time(&rawtime);//获取时间,以秒计,从1970年1月一日起算,存于rawtimetimeinfo = localtime(&rawtime);//转为当地时间,tm 时间结构strftime(CruuentTime, 11, "%Y-%m-%d", timeinfo);//格式化时间}fgets(ArchiveTime, 11, fp);//获取锁卡档案时间if (strcmp(ArchiveTime, CruuentTime)){//若无锁卡档案,或锁卡档案日期与当前日期不同,则无账户被锁定fclose(fp);return 0;}while (fscanf(fp, "%s", t) == 1){if (!strcmp(t, no)){//锁卡档案中,包含此卡号,返回1fclose(fp);return 1;}}fclose(fp);return 0;//锁卡档案中,不含此卡号,返回0}/**********查找卡号对应账户信息在链表中的地址**********/Account* FindbyNo(const char *no){for (Account *i = head; i; i = i->next){if (!strcmp(i->no, no))return i;}return NULL;}/**********锁定账户**********/void LockAccount(const char *no){FILE *fp;char CruuentTime[11];//当前日期char ArchiveTime[11];//锁卡档案日期if (!(fp = fopen("LockAccount.txt", "r"))){PR("\07");//响铃PR("error on open LockAccount.txt file!\n\n");exit(0);}{//获取当前日期time_t rawtime;struct tm * timeinfo;time(&rawtime);//获取时间,以秒计,从1970年1月1日起算,存于rawtimetimeinfo = localtime(&rawtime);//转为当地时间,tm 时间结构strftime(CruuentTime, 11, "%Y-%m-%d", timeinfo);//格式化时间}fgets(ArchiveTime, 11, fp);fclose(fp);if (strcmp(ArchiveTime, CruuentTime)){//若档案日期与当前日期不同,则说明档案已过期或无档案,新建记录。if (!(fp = fopen("LockAccount.txt", "w"))){PR("\07");//响铃PR("error on open LockAccount.txt file!\n\n");exit(0);}fprintf(fp, "%s\n", CruuentTime);}else//若记录日期与当前日期相同,则追加记录{if (!(fp = fopen("LockAccount.txt", "a"))){PR("\07");//响铃PR("error on open LockAccount.txt file!\n\n");exit(0);}}//添加记录fprintf(fp, "%s\n", no);fclose(fp);}/**********查询函数主菜单**********/void Demand(){char choose;do{system("cls");PrintBalance();PR("\t\t\t\t\t +---------+-+\n");PR("\t\t\t\t\t |查询明细\32|1|\n");PR("\t\t\t\t\t +---------+-+\n\n");PR("\t\t+-+---------+ +---------+-+\n");PR("\t\t|0|\33退出系统| | 返 回 \32|2|\n");PR("\t\t+-+---------+ +---------+-+\n\n");PR("请选择服务:");fflush(stdin);choose = getchar();switch (choose){case '1': Printetail(); break;//查询明细case '2': return;//返回case '0': FreeData(); exit(0);//退出系统default:printf("输入错误,请重新选择\n"); //解决用户可能的输入错误system("pause");}} while (1);}/**********输出余额**********/void PrintBalance(){system("cls");PR("\n\n\n\n\n\n\n\n\n\t\t+---------------+---------------+\n");PR("\t\t| 您的账户余额 \32|%-15.2f|\n", now_acc->balance);PR("\t\t+---------------+---------------+\n\n\n\n\n\n\n");}/**********输出明细**********/void Printetail(){FILE *fp;Record temp;int flag = 1;//当有记录时,置0if (!(fp = fopen("records.txt", "r"))){PR("无存取记录,请进行存取后再使用本功能\n\n");system("pause");return;}system("cls");PR("+---------+--------------+\n");PR("| 日期 | 存取金额 |\n");PR("+---------+--------------+\n");while (fscanf(fp, "%s%d-%d-%d%lf", temp.no, &temp.date.year, &temp.date.month, &temp.date.day, &temp.number) == 5){if (!(strcmp(temp.no, now_acc->no))){flag = 0;PR("|%d-%d-%d|%-14.2f|\n", temp.date.year, temp.date.month, temp.date.day, temp.number);PR("+---------+--------------+\n");}}PR("| 日期 | 存取金额 |\n");//未免记录太多看不到表头,在最后加个表头PR("+---------+--------------+\n");if (flag){system("cls");//无记录时,清除表头PR("该卡号未有任何存取记录\n\n");system("pause");return;}system("pause");//当有存取记录时,输出后等待}/**********将存款记录写入文件中**********/void Log(double money, const char *no){FILE *fp;Date CruuentTime;//当前日期if (!money)//存取为零时return;if (!(fp = fopen("records.txt", "a"))){PR("\07");//响铃PR("error on open records.txt file!");exit(0);}{//获取当前日期time_t rawtime;struct tm * timeinfo;time(&rawtime);//获取时间,以秒计,从1970年1月1日起算,存于rawtimetimeinfo = localtime(&rawtime);//转为当地时间,tm 时间结构CruuentTime.year = timeinfo->tm_year + 1900, CruuentTime.month = timeinfo->tm_mon + 1, CruuentTime.day = timeinfo->tm_mday;}fprintf(fp, "%s\n%d-%d-%d\n%f\n", no, CruuentTime.year, CruuentTime.month, CruuentTime.day, money);fclose(fp);}/**********取款主界面**********/void Withdrawal(){char choose;if (now_acc->balance < 50.0){//当余额不足50时,无法取款PR("\07");//响铃PR("您的余额不足50,无法取款\n\n");system("pause");return;}do{system("cls");PR("\n\n");PR("\t\t+-+---------+ +---------+-+\n");PR("\t\t|1|\33 100 | | 2000 \32|5|\n");PR("\t\t+-+---------+ +---------+-+\n\n");PR("\t\t+-+---------+ +---------+-+\n");PR("\t\t|2|\33 500 | | 5000 \32|6|\n");PR("\t\t+-+---------+ +---------+-+\n\n");PR("\t\t+-+---------+ +---------+-+\n");PR("\t\t|3|\33 1000 | |其它金额\32|7|\n");PR("\t\t+-+---------+ +---------+-+\n\n");PR("\t\t+-+---------+ +---------+-+\n");PR("\t\t|4|\33退出系统| |返 回\32|0|\n");PR("\t\t+-+---------+ +---------+-+\n\n");PR("请选择服务:");fflush(stdin);scanf("%c", &choose);switch (choose){case '1': WithdrawalOt(100); break;case '2': WithdrawalOt(500); break;case '3': WithdrawalOt(1000); break;case '4': FreeData(); exit(0);case '5': WithdrawalOt(2000); break;case '6': WithdrawalOt(5000); break;case '7':do{long money;PR("请输入取款金额(50的倍数):");fflush(stdin);scanf("%ld", &money);if (money < 0 || money % 50){//解决输入金额为负数、不是50的倍数的情况PR("输入有误,请重新输入\n");system("pause");continue;}WithdrawalOt(money);break;} while (1);break;case '0': return;default:PR("\07");//响铃printf("输入错误,请重新选择\n"); //解决用户可能的输入错误system("pause");continue;}{//取款完成后的菜单char choose;system("cls");PR("\n\n");PR("\t\t +---------+-+\n");PR("\t\t |继续取款\32|1|\n");PR("\t\t +---------+-+\n\n");PR("\t\t +---------+-+\n");PR("\t\t |显示余额\32|2|\n");PR("\t\t +---------+-+\n\n");PR("\t\t \n");PR("\t\t \n");PR("\t\t \n\n");PR("\t\t+-+---------+ +---------+-+\n");PR("\t\t|0|\33退出系统| |返 回\32|3|\n");PR("\t\t+-+---------+ +---------+-+\n\n");PR("请选择服务:");fflush(stdin);scanf("%c", &choose);switch (choose){case '1': continue;//继续取款case '2': PrintBalance(); system("pause"); break;//输出余额case '3': return;//返回主函数case '0': FreeData(); exit(0);//退出系统default:PR("\07");//响铃printf("输入错误,请重新选择\n"); //解决用户可能的输入错误system("pause");}}} while (1);}/**********取款**********/void WithdrawalOt(long money){if (now_acc->balance < money){PR("\07");//响铃PR("您的余额不足%ld\n\n", money);system("pause");return;}PR("正在处理,请稍候...\n");now_acc->balance -= money;Save();Log(-money, now_acc->no);PR("取款成功\n\n");system("pause");}/**********存款**********/void Depositing(){long money;do{PR("请输入存款金额(50的倍数),单次存款金额不得超过20000元:");fflush(stdin);scanf("%ld", &money);if (money < 0 || money > 20000 || money % 50){//解决输入金额为负数、超过20000、不是50的倍数的情况PR("\07");//响铃PR("输入有误,请重新输入\n");system("pause");continue;}PR("正在处理,请稍候...\n");now_acc->balance += money;Save();//保存账户数据Log(money, now_acc->no);//保存存取数据PR("存款成功\n\n");system("pause");break;} while (1);}/**********保存账户信息**********/void Save(){FILE *fp;int i = 1;char ch;if (!(fp = fopen("accounts.txt", "w"))){PR("\07");//响铃PR("读取帐户信息失败!accounts.txt无法打开\n");exit(0);}for (Account *i = head; i; i = i->next)//写入账户信息fprintf(fp, "%s %s %f %s\n", i->no, i->name, i->balance, i->password);fclose(fp);}/**********修改密码**********/void Modifiy(){char oldpass[7], newpass1[7], newpass2[7];do{PR("请输入原密码:");fflush(stdin);gets(oldpass);if (strlen(oldpass) != 6){PR("密码应为6位\n");system("pause");continue;}if (strcmp(oldpass, now_acc->password)){//解决密码输入有误,出于安全性的考虑,原密码输入错误时不提供返回功能PR("密码有误,请重新输入\n\n");system("pause");continue;}elsebreak;} while (1);do{PR("请输入六位新密码:");fflush(stdin);scanf("%s", newpass1);if (strlen(newpass1) != 6){PR("密码应为6位\n");system("pause");continue;}PR("请再次输入新密码:");fflush(stdin);scanf("%s", newpass2);if (strcmp(newpass1, newpass2)){//两次输入密码不一致时PR("密码不一致(输入*取消修改)\n");fflush(stdin);if (getchar() == '*')break;}else{//输入一致时strcpy(now_acc->password, newpass1);//修改密码Save();//保存用户数据PR("密码修改成功!\n\n");system("pause");break;}} while (1);}/**********转账**********/void Transfer(){Account* aimsite;//转入卡号在链表中的地址long money;//转账金额if (now_acc->balance < 50){//当账户余额不足50时PR("\07");//响铃PR("您的余额不足50,无法转账\n\n");system("pause");return;}do{char aim[17];//转入卡号PR("请输入转入卡/折号(16位):");fflush(stdin);gets(aim);if (strlen(aim) != 16){PR("卡号应为16位\n");system("pause");continue;}if (!(strcmp(aim, now_acc->no))){//解决转账双方卡号相同的情况PR("双方账户相同,请核对后重试(输入*取消转账)\n");if (getchar() == '*')return;continue;}if (aimsite = FindbyNo(aim))break;//找到转入卡号对应信息时else{PR("未找到该卡号,输入*取消转账\n");if (getchar() == '*')return;continue;}} while (1);PR("汇款目标用户名为:%s\n", CoverUpName(aimsite->name));PR("是否确认无误?(输入*确认,否则退出)");fflush(stdin);if (getchar() != '*')return;do{PR("请输入转账金额(50的倍数):");fflush(stdin);scanf("%lu", &money);if (now_acc->balance < money){PR("\07");//响铃PR("您的余额不足%lu,请重新输入转账金额\n\n", money);system("pause");continue;}if (money % 50){//当输入金额不是50的倍数时PR("\07");//响铃PR("输入有误,请重新输入\n");continue;}PR("转账中,请稍候...\n");now_acc->balance -= money;aimsite->balance += money;Save();//保存账户数据Log(-money, now_acc->no);//当前账户存取记录Log(money, aimsite->no);//转入卡存取记录PR("转账成功\n\n");system("pause");break;} while (1);}/**********掩盖部分用户名**********/char *CoverUpName(const char *name){char temp[20];strcpy(temp, name);int words = 0;//用于存放姓名的字数for (char* i = temp; *i; i += 2)words++;//计算姓名的字数switch (words){case 2:temp[0] = '*', temp[1] = '*';//当姓名字数为2时,掩盖姓strcpy(temp + 1, temp + 2);//消除一个*号break;case 3:temp[2] = '*', temp[3] = '*';//当姓名字数为3时,掩盖名字中的第一个字strcpy(temp + 3, temp + 4);//消除一个*号break;default:temp[0] = '*', temp[1] = '*', temp[2] = '*', temp[3] = '*';//姓名字数大于3时,掩盖姓和名字中的第一个字strcpy(temp + 2, temp + 4);//消除两个*号}return temp;}/**********释放链表空间**********/void FreeData(){Account* t;while (head){t = head;head = head->next;free(t);}}
展开阅读全文
  语墨文库所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
0条评论

还可以输入200字符

暂无评论,赶快抢占沙发吧。

关于本文
本文标题:C语言如何模拟ATM机的资料.doc
链接地址:http://www.wenku38.com/p-145414.html

                                            站长QQ:1002732220      手机号:18710392703    


                                                          copyright@ 2008-2020 语墨网站版权所有

                                                             经营许可证编号:蜀ICP备18034126号

网站客服微信
收起
展开