目录一、运行环境 0一、运行环境 (1)二、设计目的和意义 (1)2.1设计目的 (1)2.2设计意义 (1)三、算法思想 (1)四、模块划分 (4)五、数据结构 (5)六、程序流程图 (6)七、程序源代码 (8)八、程序调试过程分析 (18)九、测试数据 (18)十、测试结果及分析 (19)十一、小结 (23)参考文献 (24)一、运行环境硬件环境:电脑软件环境:vc++6.0二、设计目的和意义2.1设计目的此次课程设计的目的是让学生在学习完C、数据结构等课程基础上,进一步掌握设计、实现较大系统的完整过程,包括系统分析、编码设计、系统集成、以及调试分析,熟练掌握数据结构的选择、设计、实现以及操作方法,为进一步的应用开发打好基础。
2.2设计意义此次设计意义在于让我们更好的去掌握C的基本语法、函数以及Visual C++集成编译环境。
掌握树、图、链表等基本数据结构及其应用。
掌握程序流程以及基本应用方法。
应用软件工程方面的知识,熟悉软件开发的流程。
通过本课程设计,培养学生进行软件设计能力。
首先进行需求分析,针对目标对象完成程序结构设计、对象设计、主要数据结构设计、输入输出设计、人机界面设计等。
三、算法思想整个系统除了主函数外,另外还有12个函数,实现十大功能:菜单选择、输入功能、显示功能、查找功能、删除功能、排序功能、插入功能、保存功能、读取功能、修改。
各个函数的详细设计说明分别如下:1、主函数 main()利用无限次循环for(;;)和swithch()实现各函数的调用,系统根据输入的数字选项来调用相应的函数。
2、初始化函数 STUDENT *init()这是一个无参函数,里面只有一个语句,它的作用是使链表初始化,使head的值为NULL。
比如:没有这个函数的话,在你没有输入任何数据的情况下,去执行显示功能的时候会显示一些乱码!3、菜单选择函数 int menu_select();这是一个无参函数,主要实现“功能选择”的界面,在这个界面里有显示系统的九大功能,根据每个功能前面的序号进行选择,中间还显示系统当前的时间。
等执行完每一个函数功能后,按任一键回到主界面也要通过这个函数来实现!4、输入记录函数 STUDENT *create()这是一个无参函数,用来执行第学生成绩记录的输入,当学生为0时停止输入,函数结束后,带回一个指向链表头的指针head。
算法:先声明一个首节点head,并将head->next设为NULL。
每输入一个数据就声明一个新节点p,把p->next设为NULL,并且到之前列表的尾端。
5、显示记录函数 void print(STUDENT *head)这是一个不返回值的有参函数,形参为“链表头的指针”,负责对全部学生成绩记录的输出,不足之处就是不能对学生成绩进行分页显示。
算法:先将p结点的指针指向第一个结点,将p结点(即第一个结点)的数据输出。
然后再将p结点的指针指向p指针的的指针(即下一结点),将p结点(即第一结点)的数据输出。
重复执行此步聚直到p指针指向NULL为止。
6、查找记录函数 void search(STUDENT *head)这是一个不返回值的有参函数,形参为“链表头的指针”,实现按对某个学生进行查找,并显示所查找到的记录。
算法:采用线性查找法往下一个节点查找。
输入所要查找的学生的s,设一个指针变量p,先指向第一个结点,当strcmp(p->name,s) && p != NULL时,使p后移一个结点,如果p!=NULL,输出p所指的结点。
7、删除记录函数 STUDENT *delete(STUDENT *head)这是一个有参函数,形参为“链表头的指针”,先输入要删除的学生记录的学号,找到后显示该学生信息,等确认后便可按“Y”进行删除。
算法:从p指向的第一个结点开始,检查该结点中的num值是否等于输入的要求删除的那个学号。
如果相等就将该结点删除,如不相等,就将p后移一个结点,再如此进行下去,直到遇到表尾为止。
8、排序函数 STUDENT *sort(STUDENT *head)这是一个有参函数,形参为“链表头的指针”,按学生成绩的平均分高低进行排序,还可以显示名次。
9、修改函数 STUDENT *xiugai(STUDENT *head)这是一个有参数函数,形参为“链表头的指针”,首先按学生对要修改的学生记录进行查找,然后对找到的记录进行修改。
算法:采用线性查找法往下一个节点查找。
输入所要查找的学生的s,设一个指针变量p,先指向第一个结点,当strcmp(p->name,s) && p != NULL时,使p后移一个结点,如果p!=NULL,修改p所指的结点的相关记录,修改完成后对记录进行输出,然后重新调用排序sort函数,对新修改的数据进行排序。
10、插入函数 STUDENT *insert(STUDENT *head,STUDENT *new)这是一个有参函数,形参有两个,一个是“链表头的指针”,一个是“待插入指针”,按照原来成绩平均分的高低进行插入,插入后会重新进行排序,并返回。
算法:先将学生的成绩按平均分由高分到低分进行排序,再插入一个新生的结点,要求按平均分的高低顺序插入。
先用指针变量p0指向待插入的结点,p1指向第一个结点。
如果p0->average<p1->average,则待插入的结点不应插在p1所指的结点之前。
此时将p1后移,并使p2指向刚才p1所指的结点。
重复以上的步骤,直到p0->average>=p1->average为止。
这时将p0指向的结点插到p1所指结点之前。
但是如果p1所指的已是表尾结点,则p1就不应后移了。
如果p0->average比所有结点的average都小,则应将p0所指的结点插到链表末尾。
如果插入的位置既不在第一个结点之前,又不在表尾结点之后,则将p0的值赋给p2->,使p2->next指向待插入的结点,然后将p1的值赋给p0->next,使得p0->next指向p1指向的变量。
如果插入位置为第一个结点之前,则将p0赋给head,将p1赋给p0->next。
如果要插到表尾之后,应将p0赋给p1->next,NULL赋给p0->next。
最后再调用排序的函数,将学生成绩重新排序.11、保存数据到文件函数 void save(STUDENT *head)这是一个不返回值的有参函数,形参为“链表头的指针”,可以把学生记录保存在电脑上由自己任意命名的二进制文件。
12、从文件读数据函数 STUDENT *load()这是一个不返回值的有参函数,形参为“链表头的指针”,根据输入的文件地址进行读取。
四、模块划分学生成绩管理的设计,除了主函数和初始化函数外,主要还设计了十个功能函数:菜单选择、输入功能、输出功能、查找功能、删除功能、排序功能、插入功能、保存功能、读取功能、修改函数。
通过分组设计现实现部分功能函数说明如下:1、菜单选择:int menu_select();提供十种可以选择的操作,在main函数中通过switch语句调用菜单menu_select()函数,进入不同的功能函数中完成相关操作。
2、输入功能:STUDENT *create();通过一个for循环语句的控制,可以一次完成无数条记录的输入。
并将其存入链表。
3、输出功能:void print(STUDENT *head);通过一个while的循环控制语句,在指针p!=0时,完成全部学生记录的显示。
知道不满足循环语句,程序再次回到菜单选择功能界面。
4、查找功能:void search(STUDENT *head);通过strcmp来判断是否找到所需查找的学生记录,在不满足该条件时,通过while 语句完成结点的下移,最后若查找成功则完成显示。
返回主菜单界面。
5、删除功能: STUDENT *Delete(STUDENT *head);按想要删除的学生的学号首先进行查找,通过指针所指向结点的下移来完成,如果找到该记录,则完成前后结点的连接,同时对以查找到的结点进行空间的释放,最后完成对某个学生记录进行删除,并重新存储。
6、修改功能:STUDENT *xiugai(STUDENT *head);首先通过想核对想要修改的学生进行查到,相当于调用一次查找函数search,如果查找成功则对数据进行修改,最后计算其总分和平均分,调用一次排序函数sort,重新进行排序,并重新存储记录。
五、数据结构定义了一个typedef struct stu 的结构体数组,相关描述如下:#define LEN sizeof(STUDENT)typedef struct stu /*定义结构体数组用于缓存数据*/{char num[6];char name[20];int score[3];int sum;float average;int order;struct stu *next;}STUDENT;六、程序流程图6.1、程序的总体模块流程图如下:图6-16.2、删除学生记录流程图如下:图6-26.3、插入学生记录流程图如下:图6-3七、程序源代码#include <stdio.h>#include<dos.h>#include<stdlib.h> /*其它说明*/#include<string.h> /*字符串函数*/#include<ctype.h> /*字符操作函数*/#define LEN sizeof(STUDENT)typedef struct stu /*定义结构体数组用于缓存数据*/{char num[6];char name[20];int score[3];int sum;float average;int order;struct stu *next;}STUDENT;/*函数原型*/STUDENT *init(); /*初始化函数*/int menu_select(); /*菜单函数*/STUDENT *create(); /*创建链表*/void print(STUDENT *head); /* 显示全部记录*/void search(STUDENT *head); /*查找记录*/STUDENT *Delete(STUDENT *head); /*删除记录*/STUDENT *sort(STUDENT *head); /*排序*/STUDENT *insert(STUDENT *head,STUDENT *New); /*插入记录*/STUDENT *xiugai(STUDENT *head); /*修改记录*/void save(STUDENT *head); /*保存文件*/STUDENT *load(); /*读文件*//*主函数界面*/void main(){STUDENT *head,New;head=init(); /*链表初始化,使head的值为NULL*/for(;;) /*循环无限次*/{switch(menu_select()){case 1:head=create();break;case 2:print(head);break;case 3:search(head);break;case 4:head=Delete(head);break;case 5:head=sort(head);break;case 6:head=insert(head,&New);break; /*&new表示返回地址*/ case 7:save(head);break;case 8:head=load(); break;case 9:xiugai(head);break;case 10:exit(0); /*如菜单返回值为9则程序结束*/ }}}/*初始化函数*/STUDENT *init(){return NULL; /*返回空指针*/}/*菜单选择函数*/menu_select(){int n;printf("****************************************************\n");printf("\t\t Welcome to\n");printf("\n\t\t The student score manage system\n");printf("********************MENU**************************\n");printf("\t\t\t1. 输入学生记录\n"); /*输入学生成绩记录*/ printf("\t\t\t2. 输出学生记录\n"); /*显示*/printf("\t\t\t3. 查找学生记录\n"); /*寻找*/printf("\t\t\t4. 删除学生记录\n"); /*删除*/printf("\t\t\t5. 将学生成绩进行排序\n"); /*排序*/printf("\t\t\t6. 插入一个新的学生记录\n"); /*插入*/printf("\t\t\t7. 保存记录\n"); /*保存*/printf("\t\t\t8. 读取记录\n"); /*读取*/printf("\t\t\t9. 修改记录\n"); /*修改*/printf("\t\t\t10. 退出\n"); /*退出*/printf("\n\t\t 夏翠玉、洁丽.\n");printf("******************************************************\n");do{printf("\n\t\t\t输入您的选择(1~10):");scanf("%d",&n);}while(n<1||n>10); /*如果选择项不在1~9之间则重输*/return(n); /*返回选择项,主函数根据该数调用相应的函数*/ }/*输入函数*/STUDENT *create(){int i,s,k;int j=0;STUDENT *head=NULL,*p; /* 定义函数.此函数带回一个指向链表头的指针*/ system("cls");printf("\n请输入您想输入的学生个数:");scanf("%d",&k);for(j=0;j<k;j++){p=(STUDENT *)malloc(LEN); /*开辟一个新的单元*/if(!p) /*如果指针p为空*/{printf("\n输出存溢出."); /*输出存溢出*/return (head); /*返回头指针,下同*/}printf("输入学号(0:list end):");scanf("%s",p->num);if(p->num[0]=='0') break; /*如果学号首字符为0则结束输入*/printf("输入:");scanf("%s",p->name);printf("请分别输入语文、数学、英语的分数 %d scores\n",3);/*开始输入*/ s=0; /*计算每个学生的总分,初值为0*/for(i=0;i<3;i++) /*3门课程循环3次*/{do{printf("score%d:",i+1);scanf("%d",&p->score[i]);if(p->score[i]<0 || p->score[i]>100) /*确保成绩在0~100之间*/printf("Data error,please enter again.\n");}while(p->score[i]<0 || p->score[i]>100);s=s+p->score[i]; /*累加各门成绩*/}p->sum=s; /*将总分保存*/p->average=(float)s/3;/*先用强制类型转换将s转换成float型,再求平均值*/ p->order=0; /*未排序前此值为0*/p->next=head; /*将头结点做为新输入结点的后继结点*/head=p; /*新输入结点为新的头结点*/}return(head);}/* 显示全部记录函数*/void print(STUDENT *head){STUDENT *p; /*移动指针*/system("cls");p=head; /*初值为头指针*/printf("\n******************************STUDENT***************\n");printf("----------------------------------------------------\n");printf("| 学号 | | 语文 | 数学 | 英语 | 总分 | 平均成绩 | 名次 |\n");printf("------------------------------------------------------\n");while(p!=NULL){printf("| %4s | %-4s | %3d | %3d | %3d | %3d | %4.2f | %-5d|\n",p->num,p->name,p->score[0],p->score[1],p->score[2],p->sum,p->average,p->order);p=p->next;}printf("----------------------------------------------------\n");printf("**************************END*************************\n");}/*查找记录函数*/void search(STUDENT *head){STUDENT *p; /* 移动指针*/char s[5]; /*存放用的字符数组*/system("cls");printf("请输入查找者.\n");scanf("%s",s);p=head; /*将头指针赋给p*/while(strcmp(p->name,s) && p != NULL) /*当记录的不是要找的,或指针不为空时*/p=p->next; /*移动指针,指向下一结点*/if(p!=NULL) /*如果指针不为空*/{printf("\n**************************FOUND*******************\n");printf("------------------------------------------------------\n");printf("| 学号 | | 语文 | 数学 | 英语 | 总分 | 平均成绩| 名次 |\n");printf("-------------------------------------------------------\n");printf("| %4s | %4s | %3d | %3d | %3d | %3d | %4.2f | %-5d|\n",p->num,p->name,p->score[0],p->score[1],p->score[2],p->sum,p->average,p->or der);printf("-------------------------------------------------------\n");printf("**************************END************************\n");}elseprintf("\n无此记录.\n",s); /*显示没有该学生*/}/*删除记录函数*/STUDENT *Delete(STUDENT *head){STUDENT *p1,*p2; /*p1为查找到要删除的结点指针,p2为其前驱指针*/ char c,s[6]; /*s[6]用来存放学号,c用来输入字母*/system("cls");printf("请输入要删除的学生的学号: ");scanf("%s",s);p1=p2=head; /*给p1和p2赋初值头指针*/while(strcmp(p1->num,s) && p1 != NULL) /*当记录的学号不是要找的,或指针不为空时*/{p2=p1; /*将p1指针值赋给p2作为p1的前驱指针*/ p1=p1->next; /*将p1指针指向下一条记录*/}if(strcmp(p1->num,s)==0) /*学号找到了*/{printf("***********************FOUND************************\n");pri-----------------------------------------------------------\n");printf("| 学号 | | 语文 | 数学 | 英语 | 总分 | 平均成绩 | 名次 |\n");printf("-------------------------------------------------\n");printf("| %4s | %4s | %3d | %3d | %3d | %3d| %4.2f | %-5d|\n",p1->num,p1->name,p1->score[0],p1->score[1],p1->score[2],p1->sum,p1->averag e,p1->order);printf("-----------------------------------------------------\n");printf("***************************************END***************** *********************\n");printf("您确定要删除该学生的记录吗 Y/N ?"); /*提示是否要删除,输入Y 删除,N则退出*/for(;;){scanf("%c",&c);if(c=='n'||c=='N') break; /*如果不删除,则跳出本循环*/if(c=='y'||c=='Y'){if(p1==head) /*若p1==head,说明被删结点是首结点*/head=p1->next; /*把第二个结点地址赋予head*/elsep2->next=p1->next;free(p1);/*否则将一下结点地址赋给前一结点地址*/printf("\n学号为 %s 的学生记录已被删除.\n",s);printf("别忘了重新存储记录.\n");break; /*删除后就跳出循环*/}}}elseprintf("\n找不到学号为 %s 的学生记录.\n",s); /*找不到该结点*/return(head);}/*修改函数*/STUDENT *xiugai(STUDENT *head){STUDENT *q; /* 移动指针*/char s[5]; /*存放用的字符数组*/system("cls");printf("请输入查找者.\n");scanf("%s",s);q=head; /*将头指针赋给p*/while(strcmp(q->name,s) && q != NULL) /*当记录的不是要找的,或指针不为空时*/q=q->next; /*移动指针,指向下一结点*/if(q!=NULL) /*如果指针不为空*/{printf("\n************************FOUND*************************\n");int sum1,i;printf("\n请在下面输入要修改成的学生的记录.\n"); /*提示输入记录信息*/printf("学号:");scanf("%s",q->num);printf(":");scanf("%s",q->name);printf("分别输入 %d 科的分数.\n",3);sum1=0; /*保存新记录的总分,初值为0*/for(i=0;i<3;i++){do{printf("score%d:",i+1);scanf("%d",&q->score[i]);if(q->score[i]>100||q->score[i]<0)printf("Data error,please enter again.\n");}while(q->score[i]>100||q->score[i]<0);sum1=sum1+q->score[i]; /*累加各门成绩*/}q->sum=sum1;q->average=(float)sum1/3;q->order=0;printf("--------------------------------------------------------\n");printf("| 学号 | | 语文 | 数学 | 英语 | 总分 | 平均成绩| 名次 |\n");printf("--------------------------------------------------------\n");printf("| %4s | %4s | %3d | %3d | %3d | %3d | %4.2f | %-5d|\n",q->num,q->name,q->score[0],q->score[1],q->score[2],q->sum,q->average,q->or der);printf("--------------------------------------------------------\n");printf("*************************END***************************\n");head=sort(head); /*调用排序的函数,将学生成绩重新排序*/printf("\n学生 %s 已经修改成功.\n",q->name);printf("请别忘了重新存储.\n");}elseprintf("\n无此记录.\n",s); /*显示没有该学生*/return(head);}八、程序调试过程分析(1)刚开始没有那个初始化函数,程序运行后,没有输入任何数据就试得去执行显示功能,结果显示的是一些乱码!加入初始化函数后,这种现象也随之消失。