1、 目 录1 需求分析11.1问题描述 1.2 输入数据要求.11.2输出数据要求11.3开发环境和工具21.4成员分工22总体设计.32.1 总体设计思路.32.2模块结构图32.3模块说明43详细设计53.1 数据类型定义5 3.2 算法思想 63.3 具体实现 7 A 读入及保存文件模块 7 B 信息插入、删除模块 7 C 查找及显示信息模块 9 D 排序模块:按时间,类别,金额 11 E 统计模块 154测试结果及分析215总结23参考文献.25附录.261 需求分析1.1 问题描述当代大学生有着旺盛的消费需求,消费观念的超前和消费实力的滞后决定了他们特殊的消费心理和消费行为。大学生科学
2、消费观的建立和合理消费规划不仅关系到大学生健康消费心理的形成,还影响到大学生迈入社会后社会经济生活的适应能力,本系统将提供一个日常消费记录,统计,分析的平台,帮助大学生合理的管理自己的日常消费。1.2 输入数据要求消费表信息:时间,类别,品名,单价,数量,金额消费信息存放在文件中,以编号的先后顺序存放用户从键盘读入消费时间,类别,品名,单价,数量,金额,保存到文件中例如:sum:40.000000index:1 time:2009-8-4 type:1 name:hzw price:0.700000 num:5 sum:3.500000index:0 time:2010-8-9 type:1
3、name:hzw price:0.900000 num:41.3 输出数据要求打开:显示文件中的所有消费记录,提供分页显示保存:将消费表的更新结果存入文件更新:可插入、删除、修改各消费记录查找:按时间,类别、品名查找消费记录排序:按时间,类别,金额统计:求各类别消费品的总金额,求各月的消费总金额,求各年的消费总金额例如:1.4 开发环境和工具开发环境:Windows 2000开发工具:C Free5.01.5 成员分工超 人(郭振兴):系统测试、主调模块、总体设计蜘蛛侠(林莉莎):、查询模块、排序模块、更新模块 2总体设计2.1总体设计思路本设计主要包括数据录入模块,信息删除模块,查询显示模块
4、,数据排序模块, 数据统计模块.2.2模块结构图根据需求将系统划分为五个功能模块如图所示数据录入模块数据统计模块插入删除模块查询显示模块数据排序模块 个人消费管理系统2.3模块说明1.数据录入模块. 本模块的设计主要包括三个函数,struct Time(消费时间),enum TYPE(消费类型)struct ConsumeRecord(完整的消费记录)struct ConsumeRecord 函数主要实现程序的初始建库,把数据添加到文件中,其主要过程是打开文件,调用Time ,TYPE函数,将需要录入的数据从键盘输入,添加到文件中。2.信息删除模块. 本模块通过输入需要查找的条目的索引号,程序
5、循环遍历所有已存的消费条目,如果消费条目的索引号等于要删除的索引号,删除该索引号对应的消费条目,并将其后面的消费条目依次往前移动。3.查询显示模块. 本模块通过输入需要查找的条目的索引号,程序循环遍历所有已存的消费条目,直到查找完或者找到。找到后显示从record指针开始的number个条目,遍历需要查找的条目,依次显示。4.数据排序模块. 本模块交换两个条目的内容,将record数组用选择冒泡法分别以消费时间,类型,价格进行排序。5.数据统计模块. 本模块已存条目指针和已存个数如果已存条目小于等于零,退出统计, 将条目按时间排序,如果只有一条记录直接输出,如果有多条记录,则遍历所有记录并分别
6、打印如果当前记录与下一条记录年份月份相同,则将其归于一个月,并累加该月的总金额. 月份变了,打印统计月份的总金额,/将年份金额赋值为下一月份,开始记录下一月份. 3详细设计3.1数据类型定义 /时间结构体记录消费时间struct Timeint year;int month;int day;类型结构体记录消费类型enum TYPESTUDY,EAT,PLAY;/消费条目结构体,用以记录完整的消费记录struct ConsumeRecordint index;/消费索引Time time;/消费时间TYPE type;/消费类型char name256;/消费名称float price;/单价i
7、nt num;/数目float sum;/总价nt _tmain(int argc, _TCHAR* argvConsumeRecord* recordTmp;/临时条目指针int indexToDelete;/需要删除的条目的索引号int indexToFind;/需要查找的条目的索引号char sortType=0;/排序类型int nCurrent=0;/已存条目的个数int nCurrentDump;/暂存“已存条目的个数”,用以分页显示的时候,还原已存条目个数char next;/分页显示时输入变量,输入n显示下一页(十行)FILE *file;/文件指针,用以从文件读取记录,或写文
8、件ConsumeRecord* pCurrent;/现在所指向的条目的指针ConsumeRecord record100;/现存条目数组char input=o;/记录需要做的操作的变量3.2算法思想分别用时间结构体记录消费时间, 类型结构体记录消费类型, 消费条目结构体记录完整的消费记录.其中查询和删除模块通过扫描已建立的所有数据,索引出符合条件的条目,统计模块先通过以时间,类型,价格进行排序,再统计各类别消费品的总金额,各月的消费总金额,各年的消费总金额.3.3具体实现A.读入及保存文件模块将消费数据以文件的形式储存,定义一个文件指针file使其指向该文件,利用标准输入函数fopen读入文
9、件内数据。具体是用指针指向条目的第一行,判断如果已存文件数小于最大文件数,读取文件。读取一条后,指针指向下一个地方以读取下一条目,同时使读入条目数nCurrent加一。如此循环读完数据后,将文件关闭。以同样的方法打开文件,遍历所有的条目直到结束,将消费一个条目写入文件,消费条目指针指向下一个消费条目,用以将下一个消费条目写入文件,最后关闭文件。B信息插入、删除模块自定义函数DeleteRecord(ConsumeRecord* record,int& nCurrent,int index) 其中record是消费条目指针,nCurrent是已存消费条目的个数,index为索引号,利用循环遍历所
10、有的索引号,如果遇到的索引号与要删除的索引号相同,则实现调用删除函数DeleteRecord(ConsumeRecord* record,int& nCurrent,int index)功能,即:for (int i = 0;iindex=index)for (int j = i;jnumsum=pCurrent-price*pCurrent-num;pCurrent+; nCurrent+;pCurrent=&recordnCurrent;如下:C.查找及显示信息模块Record:指向消费条目记录数组,nCurrent:已存条目数,index:需要查找的条目的索引号利用ConsumeReco
11、rd* FindRecord(ConsumeRecord* record,int& nCurrent,int index)遍历所有已存的消费条目,直到查找完或者找到如果消费条目的索引号为需要查找的索引号才,找到了,返回;遍历完了没有找到,输出“not found!”即:for (int i = 0;iindex=index)return record;printf(not found!);return 0; 查找完后调用ShowRecord输出要显示的条目。ShowRecord函数功能如下:void ShowRecord(ConsumeRecord* record)printf(index:%
12、d %d-%d-%d type:%d name:%s price:%f num:%d sum:%fn,record-index,record-time.year,record-time.month,record-time.day,record-type,record-name,record-price,record-num,record-sum);然后调用显示ShowRecords查找到的从指针开始的总的条目,ShowRecords功能如下:void ShowRecords(ConsumeRecord* record,int number)for (int i=0;inumber;i+)Sho
13、wRecord(record+i);注:number:需要显示的条目数。Record:指向第一个要显示的指针。D排序模块:按时间,类别,金额具体来说是定义了一个函数,实现三种方式的排序,其中运用了switch语句,根据不同的排序类型划分了不同的case,然后选择出相应的功能来实现要求,比较实用而且简洁。函数内部是采用冒泡法排序,首先判断选择的类型然后进入相应的功能区。定义函数void SortRecord(ConsumeRecord* record,int nCurrent,char type)其中 record:排序数组头指针,nCurrent:数组的个数,type:排序类型void Sor
14、tRecord(ConsumeRecord* record,int nCurrent,char type)int i,j;switch(type)case t: /按时间排序for(i=0;inCurrent-1;i+)for(j=0;jrecordj+1.time.year)swap(&recordj,&recordj+1);else if /年份相同,比较月份(recordj.time.year=recordj+1.time.year&recordj.time.monthrecordj+1.time.month)swap(&recordj,&recordj+1);else if/年份月份相
15、同,比较日期 (recordj.time.year=recordj+1.time.year&recordj.time.month=recordj+1.time.month&recordj.time.dayrecordj+1.time.day)swap(&recordj,&recordj+1);break;/按类型排序case l:for(i=0;inCurrent-1;i+)for(j=0;jrecordj+1.type)swap(&recordj,&recordj+1);break;/按价格排序case p:for(i=0;inCurrent-1;i+)for(j=0;jrecordj+1.
16、price)swap(&recordj,&recordj+1);break;如下:E统计模块为了便于统计,现将数据进行排序,根据不同的统计方式进行不同的排序,如为了计算每年的消费总额,需要将数据按时间排序,然后进行统计,按类型排序就利于统计每个项目的消费情况。在程序中就要在统计之前根据需要调用相应的函数实现排序功能。具体如下所示:void Statistic(ConsumeRecord* record,int nCurrent)/如果已存条目小于等于零,退出if (nCurrentsum;/按年统计的总金额,将第一条记录的金额付给他double sumMonth = record-sum;/按
17、月统计的总金额,将第一条记录的金额付给他double sumType = record-sum;/按类型统计的总金额,将第一条记录的金额付给他/如果只有一条记录直接输出if (nCurrent = 1)/输出按年统计的总金额printf(year:%d sum:%fn,record0.time.year,sumYear);/输出按月统计的总金额printf(year:%d-month%d: sum:%fn,record0.time.year,record0.time.month,sumMonth);/输出按类型统计的总金额printf(type:%d sum:%fn,record0.type,
18、sumType);return;/如果有多条记录,则遍历所有记录并分别打印for (int i=0;inCurrent;i+)/如果当前记录与下一条记录年份相同,则将其归于一年,并累加改年的总金额if (recordi.time.year=recordi+1.time.year)sumYear+=recordi+1.sum;else/年份变了,打印统计年份的总金额printf(year:%d sum:%fn,recordi.time.year,sumYear);/将年份金额赋值为下一年份,开始记录下一年分sumYear=recordi+1.sum;/如果当前记录与下一条记录年份月份相同,则将其
19、归于一个月,并累加该月的总金额if (recordi.time.year=recordi+1.time.year&recordi.time.month=recordi+1.time.month)sumMonth+=recordi+1.sum;else/月份变了,打印统计月份的总金额printf(year:%d-month%d: sum:%fn,recordi.time.year,recordi.time.month,sumMonth);/将年份金额赋值为下一月份,开始记录下一月分sumMonth=recordi+1.sum;/按类型将记录排序SortRecord(record,nCurrent
20、,l);/遍历所有记录for (int i=0;inCurrent;i+)/如果当前记录与下一条记录类型相同,则将其归于同一类型,并累加改类型的总金额if (recordi.type=recordi+1.type)sumType+=recordi+1.sum;else/类型变了,打印该类型的总金额printf(type:%d sum:%fn,recordi.type,sumType);/将类型金额赋值为下一类型,开始记录下一类型sumType = recordi+1.sum;如下:/输入e则退出,否则一直运行以上是各个函数功能,在实际运行时要建立一个dos菜单输入不同的指令来实现相应的功能,即
21、下面的显示信息:提示用户选择想要的操作 4.测试结果及分析部分结果如下:本次测试主要对程序的五个模块功能进行了检验,刚开始的时候也出现了很多没有预想到的错误,接着一步步查找错误,认真分析,最终正确地实现了功能,结果与预期基本相同.最终通过给老师提问,以及自己的演示也出现了一些问题,比如:功能实现不全,以及结果显示不清楚等等.出现的显示不清楚如下: 应当按照平常习惯建立表格形式的目录,没有必要每次的结果都要在前面附带类型.这个不足在于2009年的统计处有问题.这些问题提醒了我以后做什么事情都要多方面考虑,设计这种程序关键在于它的实用性. 5.总结 经过上一个学期对C程序设计的学习,我们学习了理论
22、知识,了解了C语言程序设计的思想,这些知识都为我们的下一步学习打下了坚实的基础。通过课程设计,一方面是为了检查我们一个学期来我们学习的成果,另一方面也是为了让我们进一步的掌握和运用它,同时也让我们认清自己的不足之处和薄弱环节,加以弥补和加强。 在个人消费系统程序编写过程中也体会到了做事情一顶要细心、认真。更加知道了要掌握好基础知识。还有体会到了成功的感觉!更加体会到了团队合作的重要性(很感谢我的队友),“一个诸葛亮比不上三个臭皮匠。”知道了只有团队合作才会更好的完成设计!也体会到以后在工作中团队合作的必要性和重要性!通过本项课程设计培养了我独立思考、 综合运用所学有关相应知识的能力,掌握 工程
23、软件设计的基本方法,强化上机动手编程能力,闯过理论与实践相结合的难关!也知道了自己的动手能力不强有待进一步的提高!在设计过程中不能够把书本上的知识与实践相结合,这也就增加了设计不好该程序的想法!一次次设计错误增加了我放弃的想法!不过经过大家的努力终于完成了课程设计!完成该程序后想起自己以前的每一次对自己失去信心,就觉得并不是在知识掌握上打败了,而是自己对自己缺乏信心!只要自己对自己不失去信心相信就可以完成那些以前认为完成不了的事情!懂得了自己以后要在做任何事情时都要自信!当自己都不相信自己能够成功时还可能会获得成功吗?也知道了自己在以前的学习中有很大的不足导致在设计过程中出现了很多的问题,有些
24、地方看不懂也不知道怎么去设计,但是在设计过程中也学习了很多,掌握了自己以前没有学好的知识,虽然一时可以掌握完以前没有学好的知识,不过也给自己敲响了警钟,在学习中不可以伏于表面,要想学好每一门课程都要踏踏实实,做什么都不是给别人看的!都是要更好的掌握该门知识,提高自己的自身的修养,提高自己的能力!为以后的工作打下良好的知识基础和技能基础! 参考文献谭浩强编著.C程序设计第二版M.北京:清华大学出版社,1999陈朔鹰,陈英编著.C语言趣味程序百例精解M.北京:北京理工大学出版社,1994电脑知识与技术学术交流版J2005.2 (备注:来自网络资源)Herbert Schildit著. 戴健鹏译.
25、C语言大全 (第二版)M.北京:电子工业出版社,1994谭浩强,张基温,唐永炎编著. C语言程序设计教程.M北京: 高等教育出版社,1992秦友淑,曹化工编著. C语言程序设计教程. M武汉:华中理工大学出版社,19967.黄明等编著.21世纪进阶辅导C语言程序设计. M大连理工大学出版 附录源程序:/ 个人消费系统.cpp : 定义控制台应用程序的入口点。/#include stdafx.h#include#include#include /时间结构体记录消费时间struct Timeint year;int month;int day;/消费条目结构体,用以记录完整的消费记录struct
26、ConsumeRecordint index;/消费索引Time time;/消费时间int type;/消费类型char name256;/消费名称float price;/单价int num;/数目float sum;/总价;/读取文件。/file文件指针,record消费条目数组指针,len为消费条目数组最大长度(用以判定越界),nCurrent消费条目数组已存条目个数void ReadFile(FILE*& file,ConsumeRecord* record,int len,int& nCurrent)/打开文件data.txtfile = fopen(data.txt,r);/读取
27、文件直到结束while(!feof(file)/如果已存文件数小于最大文件数,读取文件if (nCurrentindex,&record-time.year,&record-time.month,&record-time.day,&record-type,record-name,&record-price,&record-num,&record-sum);/数组指针指向下一个地方,以读取下一条记录record+;/已存记录数加一nCurrent+;/关闭文件fclose(file);/保存文件。/file为文件指针,record消费条目数组指针,nCurrent已存消费条目条目个数void S
28、aveFile(FILE*& file,ConsumeRecord* record,int nCurrent)/打开文件data.txtfile = fopen(data.txt,w);/遍历每一个消费条目直到结束for (int i=0;iindex,record-time.year,record-time.month,record-time.day,record-type,record-name,record-price,record-num,record-sum);/消费条目指针指向下一个消费条目,用以将下一个消费条目写入文件record+;/关闭文件fclose(file);/删除消费
29、记录/record消费条目数组指针,nCurrent已存消费条目的个数,index即将删除的记录的索引号void DeleteRecord(ConsumeRecord* record,int& nCurrent,int index)/遍历现在已存的所有条目for (int i = 0;iindex=index)/删除该索引号对应的消费条目,并将其后面的消费条目依次往前移动for (int j = i;jnCurrent;j+)recordj=recordj+1;/已存消费条目减一nCurrent-;/查找消费条目/record消费条目记录数组,nCurrent已存条目数,需要查找的条目的索引号
30、ConsumeRecord* FindRecord(ConsumeRecord* record,int& nCurrent,int index)/遍历所有已存的消费条目,直到查找完或者找到for (int i = 0;iindex=index)return record;/遍历完了没有找到,输出“not found!”printf(not found!);return 0;/显示条目。/record需要显示的条目的指针void ShowRecord(ConsumeRecord* record)/输出要显示的条目printf(index:%d %d-%d-%d type:%d name:%s p
31、rice:%f num:%d sum:%fn,record-index,record-time.year,record-time.month,record-time.day,record-type,record-name,record-price,record-num,record-sum);/显示从record指针开始的number个条目/record第一个要显示的条目的指针,number需要显示的条目的个数void ShowRecords(ConsumeRecord* record,int number)/遍历需要查找的条目,依次显示for (int i=0;inumber;i+)/显示条
32、目ShowRecord(record+i);/交换两个条目的内容void swap(ConsumeRecord *pR1,ConsumeRecord *pR2)ConsumeRecord temp;temp=*pR1;*pR1=*pR2;*pR2=temp;/将record数组排序,选择冒泡排序/record排序数组头指针,nCurrent数组的个数,排序类型void SortRecord(ConsumeRecord* record,int nCurrent,char type)int i,j;/判断排序类型switch(type)/按时间排序case t:/遍历数组for(i=0;inCur
33、rent-1;i+)for(j=0;jrecordj+1.time.year)swap(&recordj,&recordj+1);/年份相同,比较月份else if (recordj.time.year=recordj+1.time.year&recordj.time.monthrecordj+1.time.month)swap(&recordj,&recordj+1);/年份月份相同,比较日期else if (recordj.time.year=recordj+1.time.year&recordj.time.month=recordj+1.time.month&recordj.time.d
34、ayrecordj+1.time.day)swap(&recordj,&recordj+1);break;/按类型排序case l: for(i=0;inCurrent-1;i+)for(j=0;jrecordj+1.type)swap(&recordj,&recordj+1);break;/按价格排序case p: for(i=0;inCurrent-1;i+)for(j=0;jrecordj+1.price)swap(&recordj,&recordj+1);break;/统计/已存条目指针,和已存个数void Statistic(ConsumeRecord* record,int nCurrent)/如果已存条目小于等于零,退出if (nCurrentsum;/按年统计的总金额,将第一条记录的金额付给他double sumMonth = record-sum;/按月统计的总金额,将第一条记录的金额付给他double sumType = record-sum;/按类型统计的总金额,将第一条记录的金额付给他/如果只有一条记录直接输出if (nCurren