C语言课程设计报告学生成绩管理系统.doc
C语言课程设计报告学生成绩管理系统 学 院 计算机学院 专 业 软件工程(4)班 年 级 2007级 姓 名 学 号 教 师 一.设计题目学生成绩管理系统二课程设计目的了解软件工程中的一些系统分析,模块分析,代码设计的概念,利用WIN-TC实现学生成绩管理系统的录入、查询、删除、统计等基本操作,使用单链表结构实现学生成绩管理,了解数据库管理的基本功能,掌握C语言中的结构体、指针、函数(系统函数、自定义函数)、文件操作等知识。通过对系统的分析和设计,进一步巩固C语言的学习,以提高对开发环境的进一步认识和综合编程能力。三 系统功能1学生基本情况录入。2 能够对已经录入的数据进行显示。3能够进行数据的插入。4删除基本数据的相关信息。5复制基本数据的相关信息。6能够从文件中读入记录。7对输入的数据进行保存。8可进行姓名的查询。如:姓陈的同学。9可进行基本数据的统计计算。如:统计每个学生各门功课的平均成绩及总分,根据总分进行名次排列。对数据进行分类合计处理,统计个班级的总分,总平均分。四系统功能模块结构图本程序利用单链表存储结构完成对学生成绩的动态管理,其基本功能模块如下图所示: 0.对表进行初始化1.输入成绩记录2.从表中删除记录3.显示所有记录13.分类合计12.索引11.追加记录10.按分排序9.复制文件8.插入记录到表中7.计算总分和均分6.加载文件5.保存记录到文件4.按姓名查找记录主程序14.退出系统 15.版本信息 图1程序功能模块结构图五程序设计及各模块函数功能简述1数据结构链表是线形表的一种,线形表分为顺序存储结构和链式存储结构。线形表的顺序存储结构的特点是逻辑关系上相邻的两个元素物理位置上也相邻,因此可以随机存取表中任一元素。链式存储结构的特点是用一组任意的存储单元存储线形表的数据元素。链表的最大的优点是对表的添加、删除、查找、排序等操作比较方便,因此采用链表来存储学生相关信息。且对结点的定义如下:typedef struct z1 /*定义数据结构*/ char no11; /*10位学号*/ char name15; /*姓名*/ int scoreN; /*成绩*/ float sum; /*总分*/ float average; /*平均分*/ int order; /*排名*/ struct z1 *next; STUDENT;2.main()主函数主函数是程序入口,采用模块化设计。首先在主程序中打印欢迎界面,声明一些必要变量,作一无限循环程序,循环体为一开关语句,该语句设置一个断点,其条件值是通过调用主菜单函数得到的返回值,根据该值,调用相应的功能函数,同时设置一个断点,当返回值为一定条件时结束程序。3menu_select()主菜单为了美化界面,制作单边框窗口,在窗口中显示主菜单。通过putch()输出图形符号的ASCII码值(十六进制),达到显示的目的。利用Windows函数制作显示窗口,该窗口与边框位置,大小基本一致,通过过仔细计算且多次调试后得到其坐标值,用函数gotoxy()来实现光标的移动。设置文本和背景色输出菜单项。恢复原窗口,设计输入选择项,返回主函数。相关的一些函数如下:window、textbackground、clrscr、textcolor、cprintf、bioskey、gotoxy、gettext、puttext、putch。 putch(0xda); /*输出左上角边框*/ putch(0xc4); /*输出上边框水平线*/ putch(0xbf); /*输出右上角边框 */ gotoxy(10,i);putch(0xb3); /*输出左边的垂直线*/ gotoxy(63,i);putch(0xb3); /*输出右边的垂直线*/ putch(0xc0); /*输出左下角边框*/ putch(0xc4); /*输出下边框水平线*/ putch(0xd9); /*输出右下角边框*/ 对菜单选项的选择是利用移动光标按回车键进行选择。4init()初始化单链表需要一个头指针来指向表的第一个结点,对单链表的访问是从头指针开始的。初始化单链表为空,用NULL表示,该值在头文件stdio.h中定义为常数0。5create()创建链表当用户选择输入增加记录后,进入该函数,输入学生信息,并把信息加入链表。在输入过程中,有相关提示,如学号是十位,格式为字符型。同时对某些信息作了限定,如输入分数(0100) ,若输入分数不在这个范围内,则系统 提示重新输入,但是要求输入分数输入了非数字的代码,如“Z”,则会出现死循环。因此在输入基本信息时,若要返回主菜单,请在“enter no:”时输入*以便返回主菜单。当输入结束后,系统自动计算该生的总分和平均分,并将名次置0,待排序结束后赋予新值。数据输入结束后返回链表的头指针到方函数。在生成链表时,每次新输入的结点放在表头,这样最先输入的结点存放在最后。6delete()删除结点删除指定学号的学生记录。输入要删除的结点的学号,根据学号顺序查找结点,如果没找到,则输出没有找到的信息;否则显示找到的结点信息。如果删除的是头结点,则修改头指针,将该结点的前趋指针指向其后继结点,然后释放该结点。7append()追加记录到文件尾当想要在文件尾增加一条记录时使用该函数,首先输入新结点信息,然后输入要追加的文件名,按追加方式打开文件,将新信息写入文件。8insert()插入结点在指定结点前面插入新结点,申请空间得到指针info,输入新结点信息,存放info中,设链表头指针为h,p为指定结点的指针,q为p的前趋指针。从头结点开始循环移动指针p查找指定结点,查找和插入时分两种情况处理:1).指针p为空,如果p等于h,说明链表为空,则新结点即为头结点,修改指针h=info。否则,说明表中没有指定结点,则新结点插入在表尾部,此是q把指的结点是最后一个结点,所以修改指针q->next=info。2).指针p不为空,如果p等于h,说明新结点插入在当前第一个结点之前,为新的头结点,修改指针info->next=p,h=info。否则,说明新结点的位置应在q和p两个结点之间,修改指针info->next=p,q->next=info。9print()显示所有记录采用顺序访问的方法显示和查找记录,定义一个指向结点的临时变量p,初值为单链表的头指针,输出指针所记录的数据后,将指针后移一个记录,直到p指针值为空,则所有记录输出完毕。10.search()查找结点按照 姓名 来查找记录。从头结点开始顺序查找, 若没有相同记录显示没有,遇到 一个匹配的记录则显示此记录, 后到尾结点结束。11.save()保存记录到文件将学生信息保存到指定的文件中。按照文件读写要求,先定义一个指向文件的指针,输入要保存的磁盘文件名,如果输入的是绝对路径,则文件保存到指定的位置;如果只要文件名,则文件保存在TC默认的路径。如果文件打不开,则退出程序,否则选择一种写文件方式,打开文件。如果文件打不开,则退出程序,否则选择一种写文件方式,从链表的头指针开始,顺序将记录写入文件,直到所有记录写完,标志就是移动指针为空。12.load()从文件中加载记录按照文件读写要求,先定义一个指向文件的指针,输入要读入数据的磁盘文件名,然后确定文件的打开方式。如果文件打不开,则退出函数,否则选择一种读文件方式,从文件头开始,将记录读入内存,直到文件尾。文件打开方式和读入方式的确定要依据输出文件的打开方式和写入方式,以名数据读入错误。如果输出文件是二进制文件,块写操作,读入也应设置为二进制打开方式,块读取方式。每读入一条记录,都要做好指针链接关系,本函数将新结点链接到当前链表的尾部,链表的顺序和文件保存的顺序一致。13.copy()备份文件将文件读写功能结合到一起,先输入源文件名,再输入目标文件名,然后利用文件读写函数将源文件中的信息写到目标文件中,以达到备份文件的目的。puter()计算所有学生课程的总成绩成绩和总平均成绩 15.sort()排序本函数实现按总分排序的功能。在算法上,选择直接插入算法,即:每步将一个待排序的按其排序码值的大小插到前面已经排好序的表中,直到全部插入为止。先将链表的头结点看作是已经排好序的结点,然后取下一个结点作为待排序的结点,插入到已排好序的表中。其具体做法为:(1).先将原表头结点作为新排好序表的头结点h,原表下一个结点作为原表头结点h1。(2).原表头结点为待排序结点,将其总分与新表结点的总分进行比较,如果待排序结点总分大,则插在表头,否则插入在其后,原表头结点后移一位。(3).重复第二步,即将原表头结点的总分和新表结点的总分进行比较,如果待排序结点总分小,则移动新表指针,直到找到合适的位置将其插入。当原表为空时,所有结点排序完毕。排好序后,系统自动将名次数据写入结点数据域的order中。16.index()索引定义临时指针后,将原表的头指针所指的下一个结点作头指针,再使第一个结点定为新表的头结点。当原表不为空时,进行排序。17.total()分类合计追加班别信息,对各班的总成绩和总平均成绩进行统计并显示。18.exit()退出程序 19.auther()版本信息 显示与本系统相关的信息。六结果欢迎界面 主菜单输入界面删除界面显示界面搜索界面加载界面统计界面版本界面七心得体会 在本次课程设计中,先使用结构化分析方法对系统进行分析,将整个系统细分为几个模块,再针对每个小模块编写代码。通过本次课程设计的学习,学会了很多东西,了解了开发一个系统的一些步骤。尽管大部分都参考权威书籍的代码,但是在编写代码过程中还是加深了对链表的了解程度。开发工具用的是WIN-TC ,而目前用得比较多的应用程序的开发系统都是可视化的集成开发环境,比如Visual C+等,但是在底层开发比如硬件驱动程序的开发上,直接写出优秀的源代码还是一个程序员必须掌握的。所以 ,作为计算机软件专业的学生,我们都应该努力去做好! 源代码/*11.3.2 源程序*/*xue sheng guan li xi tong.c*/*头文件(.h)*/#include "stdio.h" /*I/O函数*/# include "bios.h" /*ROM基本输入输出函数*/#include "stdlib.h" /*其它说明*/#include "dos.h" /*dos接口函数*/#include "string.h" /*字符串函数*/#include "conio.h" /*屏幕操作函数*/#include "mem.h" /*内存操作函数*/#include "ctype.h" /*字符操作函数*/#include "alloc.h" /*动态地址分配函数*/#define N 3 /*定义常数*/typedef struct z1 /*定义数据结构*/ char no11; char name15; int scoreN; float sum; float average; int order; struct z1 *next; STUDENT;/*以下是函数原型*/STUDENT *init(); /*初始化函数*/STUDENT *create(); /*创建链表*/STUDENT *delete(STUDENT *h); /*删除记录*/void print(STUDENT *h); /* 显示所有记录*/void search(STUDENT *h); /*查找*/void save(STUDENT *h); /*保存*/STUDENT *load(); /*读入记录*/void computer(STUDENT *h); /*计算总分和平均分*/STUDENT *insert(STUDENT *h); /*插入记录*/void append(); /*追加记录*/void copy(); /*复制文件*/STUDENT *sort(STUDENT *h); /*排序*/STUDENT *index(STUDENT *h); /*索引*/void auther(); /*版本信息*/ void total(STUDENT *h); /*分类合计*/int menu_select(); /*菜单函数*/*主函数开始*/main() int i; STUDENT *head; /*链表定义头指针*/ head=init(); /*初始化链表*/ printf("nnnnnnnnn"); printf("tt 444444444444444444444444444444444444444444444444n"); printf("tt 6 Welcome to the students-score System! 6 n"); printf("tt 6 -Chen Tian Lin- 6 n"); printf("tt 444444444444444444444444444444444444444444444444n"); for(;) /*无限循环*/ switch(menu_select() /*调用主菜单函数,返回值整数作开关语句的条件*/ /*值不同,执行的函数不同,break 不能省略*/ case 0:head=init();break; /*执行初始化*/ case 1:head=create();break; /*创建链表*/ case 2:head=delete(head);break; /*删除记录*/ case 3:print(head);break; /*显示全部记录*/ case 4:search(head);break; /*查找记录*/ case 5:save(head);break; /*保存文件*/ case 6:head=load(); break; /*读文件*/ case 7:computer(head);break; /*计算总分和均分*/ case 8:head=insert(head); break; /*插入记录*/ case 9:copy();break; /*复制文件*/ case 10:head=sort(head);break; /*排序*/ case 11:append();break; /*追加记录*/ case 12:head=index(head);break; /*索引*/ case 13:total(head);break; /*分类合计*/ case 14:exit(0); /*如菜单返回值为14程序结束*/ case 15:auther(); /*版本信息*/ /*菜单函数,返回值为整数*/menu_select() char *f="22111111111 SCORES MENU 11111111122", /*定义菜单字符串数组*/ " 0. init list ", /*初始化*/ " 1. Enter list ", /*输入记录*/ " 2. Delete a record from list ", /*从表中删除记录*/ " 3. print list ", /*显示单链表中所有记录*/ " 4. Search record on name ", /*按照姓名查找记录*/ " 5. Save the file ", /*将单链表中记录保存到文件中*/ " 6. Load the file ", /*从文件中读入记录*/ " 7. computer the score", /*计算所有学生的总分和均分*/ " 8. insert record to list ", /*插入记录到表中*/ " 9. copy the file to new file", /*复制文件*/ "10. sort to make new file", /*排序*/ "11. append record to file", /*追加记录到文件中*/ "12. index on nomber", /*索引*/ "13. total on nomber", /*分类合计*/ "14. Quit " , /*退出*/ "15. auther ", /*版本信息*/ "535 Enter the * to return when need ! 535", ; char s80; /*以字符形式保存选择号*/ int i; int key=0; /*记录所压键值*/ int c=0; gotoxy(25,25); /*移动光标*/ printf("press any key enter menu.n");/*压任意键进入主菜单*/ getch(); clrscr(); /*清屏*/ textcolor(YELLOW ); /*设置文本颜色为黄色*/ textbackground(BLUE ); /*设置背景颜色为蓝色*/ gotoxy(10,2); putch(0xda); /*输出左上角边框*/ for(i=1;i<53;i+) putch(0xc4); /*输出上边框水平线*/ putch(0xbf); /*输出右上角边框 */ for(i=3;i<22;i+)/*输出左右两边的垂直线*/ gotoxy(10,i);putch(0xb3); gotoxy(63,i);putch(0xb3); gotoxy(10,22);putch(0xc0); /*输出左下角边框*/ for(i=1;i<53;i+) putch(0xc4); /*输出下边框水平线*/ putch(0xd9); /*输出右下角边框*/ window(11,3,62,21); /* 制作显示菜单的窗口,大小根据菜单条数设计*/ clrscr(); /*清屏*/ for(i=0;i<18;i+) gotoxy(10,i+1); cprintf("%s",fi); /*输出菜单项数组*/ i=1; gotoxy(10,2); /*设置默认选项在第一项*/ textbackground(BLINK );/*设置背景颜色为浅绿*/ cprintf("%s",f1); /*输出菜单项,表示选中*/ gotoxy(10,2); /*移动光标到菜单的第一项*/ while(key!=13) /*所压键不是回车键时*/ while(bioskey(1)=0); /*查询是否压下了一个键*/ key=bioskey(0); /*返回下一个在键盘压下的键*/ key=key&0xff?key&0xff:key>>8; /*对所压的键进行判断*/ gotoxy(10,i+1); textbackground(BLUE);/*设置背景颜色为蓝色*/ cprintf("%s",fi); /*输出菜单项*/ if(key=72) i=i=1?16:i-1; /*如压向上光标键,i减1,如已到第一行再上移,则到最后一行*/ if(key=80)i=i=16?1:i+1; /*如压向下光标键,i加1,如已到最后一行再下移,则到第一行*/ gotoxy(10,i+1); /*光标移动i的下一项*/ textbackground(LIGHTRED); /*将背景颜色设为浅红*/ cprintf("%s",fi); /*输出菜单项*/ c=i-1; /*给代表菜单选项的整数赋值*/ textbackground(CYAN ); /*设置背景颜色为青色*/ window(1,1,80,25); /*恢复原窗口大小*/ return c; /*返回代表菜单选项的整数值*/ STUDENT *init() return NULL; /*1创建链表*/STUDENT *create() int i; int s; STUDENT *h=NULL,*info; /* STUDENT指向结构体的指针*/ for(;) info=(STUDENT *)malloc(sizeof(STUDENT); /*申请空间*/ if(!info) /*如果指针info为空*/ printf("nout of memory"); /*输出内存溢出*/ return NULL; /*返回空指针*/ inputs("enter no:",info->no,11); /*输入学号并校验*/ if(info->no0='*') break; /*如果学号首字符为则结束输入*/ inputs("enter name:",info->name,15); /*输入姓名,并进行校验*/ printf("please input %d score n",N); /*提示开始输入成绩*/ s=0; /*计算每个学生的总分,初值为0*/ for(i=0;i<N;i+) /*N门课程循环N次*/ do printf("score%d:",i+1); /*提示输入第几门课程*/ scanf("%d",&info->scorei); /*输入成绩*/ if(info->scorei>100|info->scorei<0) /*确保成绩在0100之间*/ printf("bad data,repeat inputn"); /*出错提示信息*/ while(info->scorei>100|info->scorei<0); s=s+info->scorei; /*累加各门课程成绩*/ info->sum=s; /*将总分保存*/ info->average=(float)s/N; /*求出平均值*/ info->order=0; /*未排序前此值为0*/ info->next=h; /*将头结点做为新输入结点的后继结点*/ h=info; /*新输入结点为新的头结点*/ return(h); /*返回头指针*/*2输入字符串,并进行长度验证*/inputs(char *prompt, char *s, int count) char p255; clrscr(); /*清屏*/ doprintf("No. name yu wen shu xue ying yu /Enter the * to return when needn"); printf(prompt); /*显示提示信息*/ scanf("%s",p); /*输入字符串*/ if(strlen(p)>count)printf("n too long! n"); /*进行长度校验,超过count值重输入*/ while(strlen(p)>count); strcpy(s,p); /*将输入的字符串拷贝到字符串s中*/*3输出链表中结点信息*/void print(STUDENT *h) int i=0; /* 统计记录条数*/ STUDENT *p; /*移动指针*/ clrscr(); /*清屏*/ p=h; /*初值为头指针*/ printf("nnn*STUDENT SCORES*n"); printf("| rec|nO | name |yu wen|shu xue|ying yu| sum | ave |order|n"); printf("|-|-|-|-|-|-|-|-|-|n"); while(p!=NULL) i+; printf("|%3d |%-10s|%-15s|%6d|%7d|%7d| %4.2f | %4.2f | %3d |n", i, p->no,p->name,p->score0,p->score1,p->score2,p->sum,p->average,p->order); p=p->next; printf("*end*n");/*4删除记录*/STUDENT *delete(STUDENT *h) STUDENT *p,*q; /*p为查找到要删除的结点指针,q为其前驱指针*/ char s11; /*存放学号*/ clrscr(); /*清屏*/ printf("please deleted no n"); /*显示提示信息*/ scanf("%s",s); /*输入要删除记录的学号*/ q=p=h; /*给q和p赋初值头指针*/ while(strcmp(p->no,s)&&p!=NULL) /*当记录的学号不是要找的,或指针不为空时*/ q=p; /*将p指针值赋给q作为p的前驱指针*/ p=p->next; /*将p指针指向下一条记录*/ if(p=NULL) /*如果p为空,说明链表中没有该结点*/ printf("nlist no %s studentn",s); else /*p不为空,显示找到的记录信息*/ printf("*have found*n"); printf("|no | name |yu wen|shu xue|ying yu| sum | ave |order|n"); printf("|-|-|-|-|-|-|-|-|n"); printf("|%-10s|%-15s|%6d|%7d|%7d| %4.2f | %4.2f | %3d |n", p->no, p->name,p->score0,p->score1,p->score2,p->sum, p->average,p->order); printf("*end*n"); getch(); /*压任一键后,开始删除*/ if(p=h) /*如果p=h,说明被删结点是头结点*/ h=p->next; /*修改头指针指向下一条记录*/ else q->next=p->next; /*不是头指针,将p的后继结点作为q的后继结点*/ free(p); /*释放p所指结点空间*/ printf("n have deleted No %s studentn",s); printf("Don't forget saven");/*提示删除后不要忘记保存文件*/ return(h); /*返回头指针*/*5查找记录*/void search(STUDENT *h) STUDENT *p; /* 移动指针*/ char s15; /*存放姓名的字符数组*/ clrscr(); /*清屏幕*/ printf("please enter name for searchn"); scanf("%s",s); /*输入姓名*/ p=h; /*将头指针赋给p*/ while(strcmp(p->name,s)&&p!=NULL) /*当记录的姓名不是要找的,或指针不为空时*/ p=p->next; /*移动指针,指向下一结点*/ if(p=NULL) /*如果指针为空*/ printf("nlist no %s studentn",s); /*显示没有该学生*/ else /*显示找到的记录信息*/ printf("nn*havefound*n"); printf("|nO | name |yu wen|shu xue|ying yu| sum | ave |order|n"); printf("|-|-|-|-|-|-|-|-|n"); printf("|%-10s|%-15s|%6d|%7d|%7d| %4.2f | %4.2f | %3d |n", p->no,p->name,p->score0,p->score1,p->score2,p->sum,p->average,p->order);