C语言课程设计报告银行账户管理系统231132姜紫阳菜单一、整体需求分析二、程序设计思想三、程序流程框架示意四、程序主要片段及说明五、程序优劣性分析及改进点六、自我总结及感想七、附录:源代码一、总体需求分析问题描述设计一个银行账户管理程序,账户的信息有账号(唯一)、身份证(唯一)、余额、密码等,允许用户进行如下操作:开户、取款、转账、查询、修改密码,一个用户只能有一个户头,应检测身份证是否被注册。基本要求程序运行时,可以由用户选择进行何种操作,开户操作要求输入用户信息后检测身份证是否被使用,不允许用户透支,根据账号可以进行用户的信息查询,所有的账户信息应存放到一个文件中,可以随时的访问和更新。二、程序设计思想银行账户管理的实现由于人数的不确定性,避免内存的浪费以及出现数组元素不够的情况,选择使用链表进行操作。为保证储户信息可以保存下来,在程序文件夹里面创建了一个“shuju.txt”的文件用以保存数据。程序主要包括信息数据的处理以及程序操作界面两个部分。因此,我创建了一个工程,主要包括4个部分。第一个部分是“function.h”,在里面申明了我要使用的所有函数,并且定义一个用户类ctm,数据成员主要有身份证号码(id)、账号(ac)、密码(co)、余额(am)以及指向自身的指针(next)等内容,用以生成链表,保存用户信息。同时,定义了一个ctm型的head指针,用以记录生成链表的头指针。第二部分为“function.c”文件,在这个c文件中,我主要写了8个函数,首先是基础的从文件中读取数据形成链表的函数data()。然后是将文件格式化并将链表的信息写到文件中的函数datanew()。还有就是通过账号读取账户地址,并将ctm型变量的地址返回的*acread(ac)函数,在此基础上,写了5个函数用以实现开户、取款、转账、查询、修改密码。开户函数主要是先检测身份证是否被使用,然后在链表的结尾加上一个新的数据,并让原链表尾指向新的数据首地址。取款函数主要为读出账户地址,并改变里面的am项,修改密码函数与取款函数类似。转账函数是在取款函数的基础上,分别读取当前用户的地址和目标用户的地址,并修改其中的am数据。查询函数主要为读出目标地址,然后显示其中的数据。操作界面上,我定义了一个“control.c”的文件,在里面,主要包括了4各menu()函数用以显示我想要显示的菜单。还有3个关键的函数,有初始化函数init()、进入系统的函数*enter()、还有退出的函数iexit()。初始化函数主要是使用了建立链表的函数用以读取数据生成链表,然后改变菜单,等待进入系统。enter函数主要实现核对账号密码的信息,并返回用户数据的指针*now,用以以后的各个功能。还有退出函数iexit(),使用datanew()保存用户信息,并显示退出界面。最后一个部分为“main.c”在里面,我只写了一个主函数main。主函数中,写了系统整体的框架。将各个函数整合。实现循环选择等功能。三、程序流程框架示意四、主要程序片段及说明1、主函数:voidmain(){structctm*now;inti=2,j,k=1;init();while(i==2){menu1();menu3();scanf(%d,&i);if(i==2){开始选择开户功能选择修改密码查询转账取款继续????退出登录系统open();data();CLR;}}now=enter();while(k==1){CLR;menu1();menu4();scanf(%d,&j);switch(j){case1:out(now);break;case2:read(now);break;case3:move(now);break;case4:change(now);break;default:printf(输入错误\n);break;}printf(输入1返回操作界面,输入2退出\n);scanf(%d,&k);}iexit();}主函数主要实现流程图所示的过程,先初始化,形成链表并改变head指针指向链表首地址,清屏显示菜单。定义了两个开关,i和k,i设为2,进入循环,让用户在菜单1中选择开户或者直接登录,如果选择开户,那么i仍为2,开完户后继续选择开户或登录,如果选择登录,则i变为1退出循环,清屏显示菜单2(CLR为定义过得清屏函数system(“cls”))。k默认设置为1,进入循环,进入后选择相应的功能,完成后由用户选择是否继续,如果继续,输入1,k仍为1,继续循环。输入其他的结束循环并进入自己定义的退出函数iexit退出。2、读取文件信息,新建链表的函数:voiddata(){longid,ac,am;intco;structctm*count,*p;head=count=NULL;fp=fopen(shuju.txt,r);while(!feof(fp)){p=(structctm*)malloc(sizeof(structctm));fscanf(fp,%ld%ld%d%ld,&id,&ac,&co,&am);p-id=id;p-ac=ac;p-co=co;p-am=am;p-next=NULL;if(head==NULL)head=count=p;else{count-next=p;count=p;}}fclose(fp);}链表首地址head在头文件定义,为全局变量,用于存放链表的首地址,fp也在头文件中定义,为FILE*型的指针(经过试验,在子程序中定义FILE*fp同时在之后定义long和int型变量会出现fp未定义的情况,因此,在头文件中定义fp)。刚开始让head和count指向为NULL,打开文件,在文件流未显示读取完毕的时候,不断为p开辟空间,并读取文件数据赋予p然后让count的指向自身的变量next指向p,并把p赋给count,以此形成链表。链表首地址为head,保存在全局变量中,让以后的函数使用。3、读取用户数据地址的函数:structctm*acread(longac){structctm*f;f=head;while(f-ac!=ac){if(f-next==NULL){f=NULL;break;}f=f-next;}returnf;}定义了一个指针f,先让指针指向链表首地址,然后通过比较结构体中的ac元素与ac是否相等。如果相等,则返回f的地址,如果不相等,则f指向后一个数据,最后,当比较到最后一个数据仍不相等,则让f指向为NULL,并返回。4、开户函数:voidopen(){intj=0,co;longac,am,id;structctm*f,*p;p=(structctm*)malloc(sizeof(structctm));printf(请输入身份证号码\n);while(j==0){f=head;scanf(%ld,&id);while(f-id!=id){if(f-next==NULL){if(f-id!=id){f-next=p;printf(请输入账号\n);scanf(%ld,&ac);p-ac=ac;printf(请输入密码\n);scanf(%d,&co);p-co=co;printf(请输入存款金额\n);scanf(%ld,&am);p-am=am;p-next=NULL;p-id=id;j=1;break;}}f=f-next;if(f-id==id)printf(身份证已被使用,请重新输入\n);}}}开户函数中比较身份证是否被使用的部分大致与上面的读取用户数据地址的函数相同,通过不断比较输入的身份证是否相等来确定身份证是否被使用。本函数用到的比较关键的一个东西是开关j。刚开始将开关j设为0,使得函数进入循环,不断比较数据中的id是否与输入的id相等,如果比较到最后一个还不相等,说明此身份证未被使用,进行开户的操作,然后使开关变为1,跳出循环,结束。如果中途发现有一个相等了,说明身份证已被使用,告知用户已被使用,并继续循环。重新输入新的身份证号码。5、功能函数,以转账为例:voidmove(structctm*now){longnum,acc;structctm*aim;printf(请输入要转的账号\n);scanf(%ld,&acc);aim=acread(acc);while(aim==NULL){printf(账号错误,请重新输入,退出按0。\n);scanf(%ld,&acc);if(acc==0)iexit();elseaim=acread(acc);}printf(请输入要转的金额\n);scanf(%ld,&num);while(numnow-am){printf(金额不足,请重新输入,退出按0。\n);scanf(%ld,&num);if(num==0)iexit();}aim-am=aim-am+num;now-am=now-am-num;}转账函数中利用了生成链表的函数中保存的head指针,以及读取账户数据地址的函数acread所返回的地址,还有自己定义的退出函数iexit,首先读取了当前用户的数据地址now,在用acread读取了目标用户数据的地址aim。在读取了信息之后,让用户输入需要转的金额,并比较,如果金额少于用户实际金额,告知用户,并重新输入。正确输入后,让链表中的结构体元素am相应的增加和减少。实现余额的改变。6、登录函数:structctm*enter(){longac;intco;structctm*now;printf(请输入账号\n);scanf(%ld,&ac);now=acread(ac);while(now==NULL){printf(账号不存在,请重新输入\n);now=acread(ac);}printf(请输入密码\n);scanf(%d,&co);while(now-co!=co){printf(密码错误,请重新输入,退出按0\n);scanf(%d,&co);if(co==0)iexit();}CLR;menu1();menu4();return(now);}登录函数中利用了读取账户地址的函数acread,如果账户地址返回值为NULL,说明不存在该账户,要求用户重新输入,如果存在,读出该数据地址,让now指向他,然后通过其中的元素co,比较其是否相等来验证登录的正确性,如果密码也相同,则登录正确,返回指向结构体的指针now。如果密码错误,则让其继续输入。登录之后,清屏(CLR为在头文件中定义的清屏函数),然后显示登录后的菜单。7、退出函数:voidiexit(){datanew();CLR;menu1();menu2();printf(谢谢使用,按任意键退出。\n);getchar();exit(0);}退出函数中,首先我让经过操作后的链表重新写入到文件中,并让文件中原有的数据清除,其中用到了自己定义的写数据的datanew函数。然后清屏,显示我要显示的退出的菜单,用getchar吞回车,然后实现退出。五、程序优劣性分析及改进点:程序比较优秀的地方在于首先使用了链表,避免了使用数组引起的空间过度使用或者空间不足的情况。其次,数据的修改在链表中完成,文件的打开及关闭仅在初始化过程以及退出的过程中使用,提高了程序的效率。同时,用到了清屏函数system(“cls”),使得操作的界面相对来说比较清晰美观,让用户比较容易的得到正确信息。程序中定义结构体的时候其中的身份证用的是long型变量,后来发现该变量不足以保存身份证,应该改为字符型数组较为合适,用strcmp函数来比较,同时,缺少检验身份证是否输入正确,应该加上更加合适。还有,在读取数据地址的时候直接对每一个数据依次检查,效率低,可以先将数据按照账号排序,再用二分法查找效率更高。六、自我总结及感想:虽然实习时间不长便结束了,但对于这次c语言实习,我对此非常重视,因为实习不仅仅是对我们所学知识的验证,更是发现自身不足,发现所学知识欠缺的良好时机。虽然这次实习的题