资源描述
仲恺农业工程学院
工程实训报告
ATM取款机
课程名称 C语言程序设计工程实训
姓 名 林少烈
院(系) 计算机科学与工程学院
专业班级 计算机113班
学 号 201110214317
指导教师 王成
仲恺农业工程学院教务处制
目 录
1 需求分析 1
2 系统总框图和功能模块说明 1
2.1 系统总框图 1
2.2 功能模块说明 1
3 系统设计 2
3.1 主要结构体 2
3.2主要功能函数 2
3.3 关键函数的流程图 3
4 系统调试 11
5 总结 21
6 源程序清单 23
6.1头文件 23
6.2主程序 23
6.3 解除被冻结用户 40
6.4 用户注册 41
51
1 需求分析
所设计的ATM取款机应具备以下功能:
l 插入银行卡(用账号输入的方式代替);
l 密码的输入;
l 用户信息查询;
l 用户余额查询;
l 取款;
l 转账;
l 修改密码;
l 退卡。
2 系统总框图和功能模块说明
2.1 系统总框图
ATM取款机
输入用户账号
输入账号密码
查询用户信息
查询账号余额
转账
取款
修改密码
退卡
信息读取
冻结账号
图1 系统总框图
2.2 功能模块说明
Ø 输入用户账号模块:在运行时,完成用户账号的输入(代替插卡);
Ø 输入账号密码模块:①在输入账号之后,完成用户密码的输入;②在修改密码的过程中,完成用户输入旧密码的功能;
Ø 信息读取功能模块:完成用户信息的读取;
Ø 冻结账号功能模块:当输入密码3次错误时,冻结用户账号:
Ø 查询用户信息模块:完成用户的信息查询(不包括余额查询);
Ø 查询余额功能模块:完成用户余额的查询;
Ø 取款功能模块:完成取款功能模块:
Ø 转账功能模块:完成转职功能;
Ø 修改密码功能模块:完成用户修改密码功能;
Ø 退卡功能模块:完成退卡功能(即:退出程序功能)。
3 系统设计
3.1 主要结构体
用户账号、姓名、密码、余额
struct User //用户数据
{
char num[20]; //用户账号
char name[10]; //姓名
char password[7]; //密码
float balance; //余额
};
3.2主要功能函数
void read_info(); //用户信息读取
void input_num(char * num); //输入账号
void now_exist(char * num); //判断是否被冻结或不存在
void existed(char * num);
void input_password(char * p_word,char * W); //输入密码
void face(); //界面显示
void balance_refer(); //余额查询
void choose(int c); //菜单选择
void draw_money(); //取款
void set_password(); //修改密码
void input_new_password(char * old_password); //设置新密码
void tran_account(); //转账
void stamp(); //打印单条
void info_refer(); //信息查询
void out(); //退出程序
void lock(); //冻结账号
void save_info(); //存储信息
3.3 关键函数的流程图
N
i++
else l=0;
l=1;
break;
l==1
i<12
i=0
读取文件信息
printf("It cannot open !");
1
!feof(fp)
打开文件
intl=0,i=0;
now_exited 函数流程图
else
调用input_pssword 函数
s==1
判断账号是否存在
else s=0;
i++
ints=0,i;
1
i=0
i<12
s=1;
break;
用户不存在,
重新输入
冻结账号
判断密码是否正确
exited 函数流程图
input_password 流程图
choose 函数流程图
draw_money 函数流程图
i
int i=0;
打开文件
关闭文件
printf("It cannot open !");
读取文件
!feof(fp)
input_new_password 函数流程图
读取文件数据函数流程图
save_info 函数流程图
lock 函数流程图
i=0
i<U
i++
fclose(fp);
random[i]='\0';
int i;
i=0
i<12
i++
产生随机数
打开文件进行写入
printf("It cannot open !");
4 系统调试
首先运行程序,系统提示输入账号。
(1)当输入错误账号,系统提示:用户不存在,请从新输入。,
(2)当输入错误的密码时,系统提示:密码有误,请重新输入。
(3)当输入正确账号与密码时,进入主页面。
(4)主界面
(5)在主界面选择数字1,进入查询余额界面,界面显示余额。按任意键返回。
(6)在主页面选择数字2,进入取款界面,系统提示输入取款的金额,当输入不是整百数是,系统提示请输入正确的金额,请重新输入。
(8)当输入负数时,系统提示:请输入正确的金额,请重新输入。
(9)当输入超过卡里余额的数,系统会提示余额不足,请重新输入。
2
(10)当输入超过3000的数时,系统会提示:对不起,一次最多能取3000元,请重新输入。
(11)当输入正确的金额时,系统提示:交易成功,按0返回主菜单,按9继续取款。
(12)在主菜单界面选择数字3,进入修改密码界面,首先系统会提示:请输入旧密码。
(13)当输入就密码正确时,系统提示:请输入新密码(6位数)。
(14)当输入的新密码含有非数字时,系统提示:请输入正确的数字。
(15)当输入的新密码不足六位时,系统提示:请输入六位的密码。
(16)当两次输入的新密码不相同时,系统会提示:两次输入的密码不同,请重新输入。
(17)当输入两次密码都正确时,系统提示:密码修改成功,请牢记新密码。
(18)在主菜单界面选择数字4时,进入转账界面。系统提示:请输入对方的账号:
(19)当输入的账号错误时,系统会提示:用户不存在,请重新输入。
(20)当输入自己的账号时,系统会提示:不能给自己转账,请重新输入账号。
(21)当输入正确的账号时,界面会显示对方的信息。按0返回菜单,按9确定转账。
9
(22)当确定转账时,系统会提示:请输入转账金额。
(23)当输入转账的金额超过3000元时,系统会提示:对不起,一次转账不能超过3000元,请重新输入。
(24)当输入正确的金额时,系统提示:交易成功。按0返回主菜单,按9继续转账。
(25)在主菜单界面选择数字5,进入信息查询界面,界面将显示账号的信息。
(26)在主界面选择数字0,进去取款界面,系统提示:感谢您的使用,请拿回卡。
5 总结
在确认了程序设计主题之后,首先第一步是画了大概的流程图,因为ATM取款机是我们经常接触的一个机器,所以相对来说话流程图比较容易。
在画完流程图之后,就是进行代码的编写了,我采用自顶向下的方式来规划我的整个代码流程,首先是确定了大概需要哪些函数来实现所需的功能,在函数命名的时候,我并不是随便命名的,而是采用书上介绍的方法,用英文来命名。在命名过程中,由于英语功底不好的我遇到了小小的麻烦(有些单词不会拼),于是就用电子词典来解决这问题。刚开始我是把所有的自定义函数定义为void型函数。
所有的函数申明写好之后就可以开始细化了,首先确定所需结构体,然后就是头文件的定义,最后确定了所有函数的编写顺序。由于这次程序设计是ATM取款机,所有要用到文件的知识,但又没学过,所以只能先停止代码的编写来学习文件的知识。通过了两天的学习,虽然只是略学了皮毛,但是勉强看着书可以来自己新建文件并不数据存入文件中。
所有的准备工作完成后,真正的可以进行代码编写了,首先把所有的函数都编写出来(内容为空),然后根据从易到难的顺序逐个功能的编写。其顺序依次是:input_num函数(用户账号输入),input_password函数(密码输入),lock函数(冻结用户账号),read_info函数(读取文件数据),now_exit函数(检查是账号是否存在且未被冻结),existed函数(检查账号是否被冻结),face函数(主菜单),choose函数(功能选择),balance_refer函数(余额查询),draw_money函数(取款),set_password函数(修改密码),input_new_password函数(输入新密码),tran_account函数(转账),info_refer函数(查询信息),out函数(退卡)。
在写input_password函数时,没办法实现密文的输出,所以研究了很久,最后通过找资料和询问师兄才解决了这一难题,并从中学到了这一技巧。
在写lock函数时,刚开始只是用空字符来覆盖原有的账号,但是在测试时发现这样冻结的方法行不通,因为这样子冻结的话虽然原账号没了,但是在输入账号时只要直接按Enter键就可以进入输入密码的程序,所以这又是一个难题。在晚上睡觉时突然想到了曾经在课外书上看到的产生随机数的函数(rand函数),于是,第二天这个所谓的难题也解决了。
所有的函数编写完毕,想到了既然冻结了账号,肯定需要一个程序来解除冻结了的账号,所以,自己又摸索了如何解决这一问题,最后想到了一个方法:再新建一个文件(文件名为all uer information)作为后台来存储用户的信息,但这个文件存储的是所有未被冻结前和未被冻结的账号信息(即所有原始账号信息)。而解除的方法是:先读取all user information这个文件里的信息,然后把里面的信息覆盖到在前台操作的文件即可。当用户被冻结后想解除的话只需运行这个程序即可解除冻结。
写了解除冻结账号的函数后,又想到需要写一个注册账号的程序,于是也顺利的完成了,最后,通过多次的调试,把整个程序代码给完成了。
6 源程序清单
6.1头文件
/*头文件:user.h*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <time.h>
struct User //用户数据
{
char num[20];
char name[10];
char password[7];
float balance;
};
void read_info(); //用户信息读取
void input_num(char * num); //输入账号
void now_exist(char * num); //判断是否被冻结或不存在
void existed(char * num);
void input_password(char * p_word,char * W); //输入密码
void face(); //界面显示
void balance_refer(); //余额查询
void choose(int c); //菜单选择
void draw_money(); //取款
void set_password(); //设置密码
void input_new_password(char * old_password);
void tran_account(); //转账
void stamp(); //打印单条
void info_refer(); //信息查询
void out(); //退出程序
void lock(); //冻结账号
void save_info(); //存储信息
6.2主程序
/*主程序:main*/
/*模拟ATM取款机*/
#include "user.h" //自定义头文件
#define U 8
struct User user[U];
int f; //全局变量 f 是用来记录用户下标(即哪个用户)
int main()
{
char number[20]; //定义账号数组变量
input_num(number); //调用input_num函数,输入用户账号
return 0;
}
/*函数功能:输入用户账号*/
void input_num(char num[12])
{
read_info(); //输入账号前先调用函数read_info读取所以用户信息,以便后面判 //断账户是否存在以及密码是否正确
system("cls");
printf("\n\n\n\n\n\n\n\n\t\t请输入您的账号:");
gets(num);
now_exist(num); //调用exist函数检查该账号是否存在
}
/*函数功能:读取用户信息*/
void read_info()
{
int i=0;
FILE * fp;
if ((fp=fopen("user information.dat","r"))==NULL) //通过文件指针来读取用户数据信息(不包括被冻结用户信息)
{
printf("It cannot open !");
exit(0);
}
while(!feof(fp))
{
fread(&user[i],sizeof(struct User),1,fp);
i++;
}
fclose(fp);
}
/*函数功能:判断用户是否存在且未被冻结*/
void now_exist(char * num)
{
int s=0,i; // s是用来判断用户是否存在的条件,如果存在s=1,不存在s=0;
char *w="input";
while(1)
{
for(i=0;i<12;i++)
{
if ( 0 == strcmp( num, user[i].num ) ) //匹配用户
{
s=1;
f=i; //如果用户存在则跳出循环,并用变量f记录用户下标,以便后面使用。
break;
}
else s=0;
}
if (s==1)
{
input_password( user[i].password, w ); //如果用户存在,则调用input_password函数 //并把用户密码传递给它,
} //实现用户输入密码功能。
else
{
existed(num); //如果用户不存在,则调用existed函数,判断是否账号被冻结
}
}
}
/*函数功能:判断账号是否被冻结*/
void existed(char * num)
{
int l = 0, i = 0; // s是用来判断用户账号是否被冻结的条件,l=1 被冻结,l=0 说明用户不存在;
FILE * fp;
if ( ( fp=fopen("all user information.dat","r") ) == NULL )
{
printf("It cannot open !"); //用文件指针读取所有用户数据(包括被冻结用户)
exit(0);
}
while(!feof(fp))
{
fread(&user[i],sizeof(struct User),1,fp);
i++;
}
while(1)
{
for(i=0;i<12;i++)
{
if ( strcmp(num,user[i].num)==0 ) //判断输入的账号是否存在
{
l=1;
break;
}
else l=0;
}
if ( l == 1 )
{
printf("\a\n\n\t\t对不起,您的账号已被冻结,请与客服联系!\n\n\n\n");
exit(0);
}
else
{
printf("\a\n\n\t\t用户账号不存在,请重新输入!\n");
printf("\n\n\n按任意键返回!");
getch();
system("CLS");
input_num(num);
}
}
}
/*函数功能:输入密码*/
void input_password(char * p_word,char * W )
{
char password[20];
char ch;
int i, ts = 1; //ts用来统计输入密码错误的次数
do
{
if (ts<=3)
{
i = 0;
printf("\n\n\t\t请输入密码:\t");
ch = getch();
while ( ch != 13) //输入字符ch不为回车键
{
if ( ch == 8) //输入字符ch为退格键
{
printf("%c %c",ch,ch);
if ( i != 0 )
i--;
}
else
{
printf("*");
password[i] = ch;
i++;
}
ch = getch(); //继续输入字符ch
}
password[i]='\0';
if ( 0 == strcmp( W , "set" ) )
if ( (strcmp (password,"0") )==0 ) //输入0则返回主菜单
{
system("CLS");
face();
}
if ( 0 == strcmp(p_word,password) ) //密码相同
{
if ( 0 == strcmp( W , "input" ) )
{
system("CLS");
face(); //调用face函数进入主界面
}
else
if ( 0 == strcmp( W , "set" ) )
{
input_new_password( password );
}
}
else
if ( 0 != strcmp(p_word,password)) //密码不相同
{
printf("\a\n\n您输入的密码有误,请重新输入!");
ts++;
printf("\n\n\n按任意键继续!");
getch();
system("CLS");
printf("\n\n\n\n\n\n\n");
}
}
else
{
printf("\n\n\n\t 对不起,您已输入密码错误3次,您的账号已被冻结,请与客服联系!");
lock(); //输入3次错误,则提示用户账号被冻结,并调用lock函数。
}
}while(1);
}
/*函数功能:主菜单界面*/
void face()
{
int ch;
system("CLS");
printf("\n");
printf("\t---------------------------------------------------------\n");
printf("\t*********************************************************\n");
printf("\t**\t\t \t\t\t\t **\n\t**\t\t 您好!欢迎使用XX银行\t\t **\n\t**\t\t\t\t\t\t **\n");
printf("\t*********************************************************\n");
printf("\t*\t\t\t\t\t\t\t*\n\t*\t\t\t\t\t\t\t*\n");
printf("\t*\t1.查询余额\t\t\t2.取款\t\t*\n\t*\t\t\t\t\t\t\t*\n");
printf("\t*\t\t\t\t\t\t\t*\n\t*\t\t\t\t\t\t\t*\n");
printf("\t*\t3.修改密码\t\t\t4.转账\t\t*\n\t*\t\t\t\t\t\t\t*\n");
printf("\t*\t\t\t\t\t\t\t*\n\t*\t\t\t\t\t\t\t*\n");
printf("\t*\t5.信息查询\t\t\t0.退卡\t\t*\n\t*\t\t\t\t\t\t\t*\n");
printf("\t*\t\t\t\t\t\t\t*\n");
printf("\t*********************************************************\n");
printf("\t---------------------------------------------------------\n");
printf("\t\t\t请选择:");
scanf("%d",&ch);
getchar();
choose(ch);
}
void choose(int c)
{
while(1)
{
switch (c)
{
case 0: out();break; //退卡
case 1: balance_refer();break; //余额查询
case 2: draw_money();break; //取款
case 3: set_password();break; //设置密码
case 4: tran_account();break; //转账
case 5: info_refer(); break; //信息查询
default:{
system("CLS");
printf("输入有误,请重新输入!\n按任意键返回");
getch();
system("CLS");
face();
}
}
break;
}
}
/*函数功能:查询余额*/
void balance_refer()
{
system("CLS");
printf("\n\n\n\n\n\n\n\n\t\t\t您的余额是:%.2f¥\n",user[f].balance);
printf("\n\n按任意键返回!\n");
getch();
system("CLS");
face();
}
/*函数功能:取款*/
void draw_money()
{
int take,q,c;
do
{
system("CLS");
printf("\n\t\t\t\t\t\t\t\t0.返回菜单");
printf("\n\n\n\n\n\n\t\t请输入取款金额(整百数):");
scanf("%d",&q);getchar();
if (q)
{
take=q;
if ( take>=100 && take%100==0 ) //判断是否为整百数并且大于100的数
{
if (take <= user[f].balance) //判断取款数是否不超过余额
{
if ( take <= 3000 ) //判断是否超过3000
{
system("CLS");
user[f].balance -=take;
save_info(); //调用save_info函数,存储信息
printf("\n\n\n\n\n\n\t\t\t 交易成功,请提取现金!\n");
printf("\n\n\n\n\n\t\t0.返回菜单\t\t\t9.继续取款");
c=getch();
if (c=='9') //输入9继续取款
{
system("CLS");
}
else
if (c=='0') //输入0返回菜单
{
system("CLS");
face();
}
else
printf("输入错误,请重新输入!\n");
}
else
{
system("CLS");
printf("\n\n\n\n\n\n\t\t对不起,一次最多能取3000元,请重新输入!");
printf("\n\n\n\n\n按任意键返回!\n");
getch();
system("CLS");
}
}
else
{
system("CLS");
printf("\n\n\n\n\n\n\t\t\t您的余额不足,请重新输入!");
printf("\n\n\n\n\n按任意键返回!\n");
getch();
system("CLS");
}
}
else
{
system("CLS");
printf("\n\n\n\n\n\n\t\t\t请输入正确的金额!请重新输入!");
printf("\n\n\n\n\n按任意键返回!\n");
getch();
system("CLS");
}
}
else
{
system("CLS");
face();
}
}while(1);
}
/*函数功能:修改密码*/
void set_password()
{
char *w="set"; //w是为了在调用input_password函数时区分是哪个主调函数
system("CLS");
printf("\n\t\t\t\t\t\t\t\t0.返回菜单");
printf("\n\n\n\n\n\n\n");
input_password( user[f].password , w ); //调用输入密码函数
}
/*函数功能:输入新密码*/
void input_new_password(char * old_password)
{
int i,d; // d用来判断用户新密码是否为6位数
char new_password[2][7],ch;
do{
i = 0;
system("CLS");
printf("\n\t\t\t\t\t\t\t\t0.返回菜单");
printf("\n\n\n\n\n\n\t\t请输入新密码(6位数字): ");
ch = getch();
while ( ch != 13) //输入字符ch不为回车键
{
if ( ch == 8) //输入字符ch为退格键
{
printf("%c %c",ch,ch);
if (i!=0)
i--;
}
else
{
printf("*");;
new_password[0][i] = ch;
i++;
}
ch = getch(); //继续输入字符ch
}
new_password[0][i]='\0';
if ( (strcmp (new_password[0],"0") )==0 ) //输入0则返回主菜单
{
system("CLS");
face();
}
for(d=0;new_password[0][d]!=0;d++)
{
if ( (new_password[0][d]>'9') || (new_password[0][d]<'0') ) //判断密码是否是数字
{
system("CLS");
printf("\n\n\n\n\n\n\t\t\t请输入数字,谢谢!\n");
printf("\n\n\n\n\n按任意键返回!\n");
getch();
input_new_password(old_password);
}
}
if (d!=6) //判断密码是否为6位数
{
system("CLS");
printf("\n\n\n\n\n\n\t\t\t请输入6位的密码,谢谢!\n");
printf("\n\n\n\n\n按任意键返回!\n");
getch();
continue;
}
if ( (strcmp (new_password[0],"0") ) == 0 ) //输入0则返回主菜单
{
system("CLS");
face();
}
else
{
printf("\n\n\n\n\n\n\t\t请再次确认您的密码:\t ");
i = 0;
ch = getch();
while ( ch != 13) //输入字符ch不为回车键
{
if ( ch == 8) //输入字符ch为退格键
{
printf("%c %c",ch,ch);
if ( i != 0 )
i--;
}
else
{
printf("*");;
new_password[1][i] = ch;
i++;
}
ch = getch(); //继续输入字符ch
}
new_password[1][i]='\0';
if ( (strcmp (new_password[1],"0") )==0 ) //输入0则返回主菜单
{
system("CLS");
face();
}
else
if ( (strcmp (new_password[0],new_password[1]) )==0 ) //判断输入两次密码是否一致
{
strcpy(user[f].password,new_password[1]);
save_info(); //调用save_info函数,存储信息
printf("\n\n\n\t\t密码修改成功,请牢记!");
printf("\n\n按任意键返回菜单!");
getch();
system("CLS");
face();
}
else
{
system("CLS");
printf("您输入的两次密码不同,请重新输入!");
printf("\n\n\n\n\n按任意键返回!\n");
getch();
}
}
}while(1);
}
/*函数功能:转账*/
void tran_account()
展开阅读全文