资源描述
C程序设计基础课程设计设计报告链表建立学生成绩管理系统
49
2020年4月19日
资料内容仅供参考,如有不当或者侵权,请联系本人改正或者删除。
设计题目:
班 级:
姓 名:
学 号:
完成日期:
目 录
目 录 1
1. 课程设计目的和要求 1
1.1课程设计《学生成绩管理系统》的题目要求 1
2. 课程设计任务内容 2
2.1《学生成绩管理系统》主要功能实现方式 2
2.1.1链表处理数据 2
2.1.2文件读写存储学生信息 2
2.2创立数据库管理系统( DBMS) 2
3. 详细设计说明 3
3.1题目设计分析 3
3.1.1需求分析 3
3.1.2解题思路分析 3
3.2设计过程 3
3.2.1链表( 结构体) 定义 3
3.2.2函数编写 3
3.2.3编译与调试 5
4. 软件使用说明 6
4.1主界面介绍 6
4.2创立学生信息数据表 6
4.3增加数据信息 6
4.4删除数据信息 6
4.5修改信息 6
4.6查找信息 6
4.7统计功能 7
5. 课程设计心得与体会 7
5.1概述 7
5.2心得与体会 7
5.2.1数据库管理系统——链表+文件读写 7
5.2.2指针与内存 8
6. 参考文献 8
7. 附录: 部分程序清单 8
1. 课程设计目的和要求
1.1课程设计《学生成绩管理系统》的题目要求
学生包含以下信息项: 学号、 姓名、 学院、 班级、 高数成绩、 英语成绩、 C语言成绩、 总分、 平均分。
系统的主要功能包括:
1. 创立学生成绩信息文件, 根据提示输入学生的各项信息, 计算出总分和平均分, 然后按学号对学生信息进行排序, 并将排序后的学生成绩信息存储到一个二进制文件中。
2. 增加学生信息, 在原有学生信息文件的基础上增加新的学生成绩信息, 要求: 增加后的学生信息仍按学号排序, 并继续保存至原文件。
3. 删除学生信息, 提示用户输入要进行删除操作的学号, 如果在文件中有该信息存在, 则将该学号所对应的学生信息删除, 否则输出提示信息, 并提示用户选择是否继续进行删除操作。
4. 修改学生信息, 提示用户输入要进行修改操作的学号, 如果在文件中有该息存在, 则将提示用户输入该学号对应的要修改的选项, 结果保存至原文件, 并提示用户选择是否继续进行修改操作。
5. 按不同条件对学生信息进行查询操作, 输出满足条件的学生信息。
(1) 按学号查询, 输入一个学号, 输出对应的学生信息。
(2) 按姓名查询, 包括精确查询(输入全名), 模糊查询(输入姓)。
(3) 按学院查询, 输入学院名称, 输出该学院的全部学生的信息。
(4) 按班级查询, 输入班级名称, 输出该班级的全部学生的信息。
6. 按不同条件对学生成绩进行统计工作。( 两个表)
(1) 按总分对学生信息进行排序( 由高到低) , 输出排序后的信息, 并将排序后的学生信息存放到一个新的二进制文件中。
(2) 按平均分统计各个分数段的学生人数( n) ( 不及格, 60-69, 70-79, 80-89, 90-100) 。
(3) 分别找出3门课程成绩最高的学生, 并输出她们的信息。
(4) 分别统计出3门课程的不及格率(n/N), 并输出。
2. 课程设计任务内容
2.1《学生成绩管理系统》主要功能实现方式
2.1.1链表处理数据
学生作为某一对象, 其自身包含不同属性, 而每个属性的类型并不完全相同, 因而, 我们必须经过创立结构体类型的变量来定义学生信息。而用户在输入学生信息时, 并不一定指定学生人数, 因此, 需要系统动态分配内存给节点, 从而达到随时增删的目的。
但, 结构体仅能记录单个学生的信息, 并不能是所有信息产生联系, 故, 必须经过定义结构体指针变量, 来将全部的学生信息串连在一起。
2.1.2文件读写存储学生信息
在《学生成绩管理系统》中输入的学生信息只暂时存储于内存中, 当《学生成绩管理系统》关闭时, 内存会自动清除已输入的信息, 从而使学生信息丢失。因此, 必须将学生信息存入指定文件中才能实现数据的存储。
2.2创立数据库管理系统( DBMS)
《学生成绩管理系统》的实质即简易的数据库管理系统, 经过对数据的增删改查, 而创立出特定的数据处理仓库。数据库管理系统( DBSM) 能够对存入的数据进行统一的管理和控制, 具有数据的完整性, 数据的安全性, 并发控制, 和数据库的恢复等功能。利用关系模型和关系数据库系统, 使数据以二维表的形式表示, 数据结构简单清晰, 易学易用。
3. 详细设计说明
3.1题目设计分析
3.1.1需求分析
《学生成绩管理系统》是应用于学生考试成绩存储的简易系统。经过该系统能够创立、 增加、 删除、 查询学生的个人信息, 统计学生考试情况, 并能够存储到指定目录的文件中, 以达到创立数据库管理系统的目的。
3.1.2解题思路分析
首先, 分析《学生成绩管理系统》的主要功能模块。该系统组要分为两大模块: 一是, 对数据信息的增删改查; 二是, 对已有信息的统计。
其次, 分析该系统的实现方式。该系统为链表的具体应用, 需要熟练掌握链表及文件读写的相关知识。另外, 需要将每个具体功能编写为单一的被调函数, 主函数实现输入输出功能, 以达到优化程序的目的。
最后, 运行并调试程序, 更改程序错误, 优化程序功能。
3.2设计过程
3.2.1链表( 结构体) 定义
struct node
{ int num;char nam[N];char col[N];char cla[N];float math;float eng;float clan;float sum;float ave;struct node *next;};
3.2.2函数编写
l 主函数void main( )
主函数void main( ) 实现各功能的选择, 分为创立、 增加、 删除、 修改、 查询, 以及统计等功能, 而各功能分别编写为被调函数。利用while循环实现用户的人性化操作, 以达到结束程序或继续运行程序的目的。创立、 增加、 删除、 修改、 查询、 统计等被调函数, 都须写于主函数之上; 利用switch( ) 函数实现各功能的选择。对数据的增、 删、 改操作, 必须返回结构退指针, 而查找功能只需要输出即可。
l 创立链表struct node *creat(void)
创立新链表函数, 返回链表头指针。定义结构体指针变量”struct node *h=NULL, *p,*q,*r;”。h为头指针, 及数据表的表头; 动态分配内存给p, 令其始终指向新节点; 而q,r而中间辅助指针, 是链表按要求链接。在创立链表的过程中, 动态分配内存给指针p, 分别输入学生信息, 并进行数据计算与赋值。在节点连接的过程中, 经过对输入学号大小的比较while((p->num>q->num)&&(q->next!=NULL)), 按学号排序连接节点, 使学号以升序排列。在输入玩一个信息之后, 会有提示信息询问是否继续。
l 增加新节点struct node *insert(struct node *h)
增加过程与创立过程大致相同, 唯一不同的是, 增加过程需要得到形参继续增加学生信息。
l 删除节点struct node *del(struct node *h,int n)
删除节点实质就是, 将链表指针所指向的地址在内存中擦除。主要分为两种情况: 删除头指针所指向的节点地址和删除中间或结尾的节点地址。首先, 需要判断所删除节点的地址”while((p->num!=n)&&(p!=NULL))”, 然后, 进行逻辑判断, 是否存在该学号的节点, 以及判断是否为头指针, 并将p的内存空间释放掉: ”if(p==h) h=p->next;else q->next=p->next;free(p); M--;printf("M:%d\n",M); puts("Delete!");” 。
l 修改节点struct node *modify(struct node *h)
即删除和增加过成功地结合。进行
l 查找节点
查找节点, 即根据所查询的信息查找记录, 需要定义结构体指针变量p, 进行逻辑判断即可。while((strcmp(p->nam,nam)!=0)&&(p->next!=NULL)) p=p->next; if(strcmp(p->nam,nam)==0)
l 统计平均分分数段
需要根据创立( 或增加) 时计算出的平均分各分数段的个数, 来统计。分为A,B,C,D,E五个分数段, 若链表中的平均分满足判断条件, 如if((p->ave>=90)&&(p->ave<=100)), 则该分数段统计个数加一a[0]++;。
l 查找最高成绩的学生
与查找节点的算法相似, 可是逻辑判断必须满足while(p!=NULL), if(p->sum==max), 这样即使是相同分数的学生也能够同时输出到屏幕上。
l 统计不及格率
需要定义全局变量M, 然后根据各科不及格的人数n计算出不及格率: ”printf("The RATE of %c-Failer:%.2f%c\n",c,(a[2]/(float)M)*100,37);”
l 按最高分排序
按最高分排序需要建立新的链表。然后根据总分成绩进行排序。struct node *h1=NULL,*p,*a=NULL,*b,*c=NULL; struct node *sta_sor(struct node *h){ struct node *h1=NULL,*p,*a=NULL,*b,*c=NULL; if(h==NULL) {return NULL; } //creat new link point //h1 : a,b,c;//b is the latest copied information p=h; //start to copy&compare theinformation constantly while(p != NULL) { b = copyasta(p);if(c==NULL){h1 = b;//if h1 is null,insert b // printf("insert %d before h1\n",b->num); }else{ if(a == NULL && b->sum >= c->sum) { b->next = c; h1 = b;// printf("2在最前面插入%d\n",b->num); c = h1;a=NULL; p=p->next; continue; } a=h1; c=a->next; do{ if(c==NULL) { a->next=b; break; } //compare if(b->sum >= c->sum){ b->next = c; a->next = b; break; }a = c; c = c->next; } while(c != NULL); } c = h1; a = NULL; p=p->next; } return h1;}
3.2.3编译与调试
在VC++6.0的编译环境下, 当程序编写完运行时, 须先按F7, 检查语法错误, 之后按CTRL+F5运行程序, 再根据程序运行结果进行调试, 以优化程序。
在程序调试过程中, 如果要对某个被调函数进行调试, 能够标记该被调函数的某一句, 之后按F10开始调试, 如果不运行为标记的函数, 可直接按F5, 进行操作, 进入标记过的函数之后, 再逐句检查错误。逐句调试程序时, 能够根据watch等窗口查看指定变量的值, 再根据程序需要改写程序, 以避免出现栈溢出等错误。
4. 软件使用说明
4.1主界面介绍
打开程序进入主界面, 出现项目编号, 以及文字提示。可根据个人需要输入项目编号, 单机回车进入。
4.2创立学生信息数据表
在主界面输入”1”单击回车后即可进入穿件数据表界面。然后根据提示信息输入学生信息, 每个信息之间用空格( 或回车符间隔开) 。结束输入后, 系统自动返回学生信息数据表, 并询问存储文件地址。
结束信息输入后, 系统会提示, 是否继续运行《学生成绩管理系统》, 用户根据自己需要输入y或n, 从而继续或退出程序。
4.3增加数据信息
界面与创立相似, 都是按照用户需求逐一输入学生信息, 信息输入结束后, 系统自动返回学生信息数据表, 并输出到屏幕上。
不同的是增加数据信息不会删除原有信息, 而创立数据信息会返回新的链表表头, 从而创立新的链表, 而得到新的学生信息数据表。
4.4删除数据信息
在主界面选择项中, 选择3.DELETE, 进入删除功能。按照提示信息, 删除学生的学号。程序自动删除后提示是否继续删除, 否则, 提示不存在, 并询问是否继续删除。
4.5修改信息
修改信息是删除和增加的合成, 功能与界面类似。
4.6查找信息
查找信息功能, 分四个模块, 分别是按学号, 姓名, 学院, 班级查找。根据提示信息进入相应模块, 即可查询学生信息。
4.7统计功能
根据用户需要, 分别包含平均分分数段统计, 各科不及格率统计, 最高分学生信息查询, 以及按照总分排序等功能。用户能够根据提示信息, 进入相应功能模块并进行操作。
5. 课程设计心得与体会
5.1概述
本次程序设计最大的收获主要有两点: 1.对数据库的创立及原理有了更进一步了解, 2.对内存与指针更进一步了解。
5.2心得与体会
5.2.1数据库管理系统——链表+文件读写
数据库, 是存放大量数据的地方, 而现今最流行的数据库模型是关系型数据库。所谓关系型数据库, 就是存放具体信息的二维数据表, 该二维表的行称为记录, 列称为字段。记录存放的是某个具体的对象, 而字段存放的是对象所具有的属性。
联系链表的实质我们就能够发现: 其实, 一个链表就是一个数据表, 链表中的每一个节点就是数据表中的记录( 对象) , 而链表的数据成员就是数据表记录( 对象) 中对应的字段( 属性) 。因此, 我们能够明白, 其实链表就是要记录过个对象不同属性的一种变量类型。
而链表的操作过程都是在内存中完成的, 不能存储到磁盘中, 因此, 就产生了另外一种C语言的功能: 文件读写。
文件读写, 是将内存中得到的数据存储到磁盘中, 以达到长期的数据存储和处理的目的。
这样, 我们不难发现, 其实, 链表+文件读写就是简易的数据库管理系统( DBMS) 。自然, 这也是学习链表和文件读写的根本目的。因为, 只有熟练掌握链表和文件读写, 才能更好地进行数据挖掘, 和数据开发, 才能对大量数据进行高效率的处理。
5.2.2指针与内存
在刚开始学习C语言之时, 我一直有一个疑问: ”为什么还要保留这种会造成内存溢出的指针概念? ”现在, 我终于明白了!
指针变量, 简称”指针”, 其实就是存储内存地址的变量。我们知道栈存储区为静态变量和形参分配内存空间, 而堆存储区为函数动态分配内存。而内存分配时其地址是随机的, 比如0xcccccccc, 而该数是超越内存大小的, 是随机分配的, 会导致内存溢出, 无法进行程序。因此, 程序员必须清楚指针所指向的内存地址, 否则会出现内存错误。
然而, 即使指针会导致内存出错, 也不能否定指针的作用。因为, 指针是联系程序和内存的关键, 进行基础的内存操作时, 必须使用指针。譬如, 将已建成的链表, 以某个链表中的成员( 属性) 重新排序, 就必须经过指针进行链表的重建。指针是基础操作, 而基础操作才是程序员的工作根本。C语言是低级的高级语言, 能够经过指针的使用, 来操作内存。因而, 指针概念的保留是必然的。
6. 参考文献
《程序设计基础( C语言) 》
7. 附录: 部分程序清单
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
#define N 100
int M=0;//amount of stu
struct node
{
int num;
char nam[N];
char col[N];
char cla[N];
float math;
float eng;
float clan;
float sum;
float ave;
struct node *next;
};
#define L sizeof(struct node)//the length of struct node
//list the link member informatin
void list(struct node *h)
{
struct node *p;
if(h==NULL)
puts("Empty!");
else
{
p=h;
puts("The student's Information:\nNo.\tName\tCollege\tClass\tMath\tEnglish\tC_lan\tTotal\tAve");
while(p!=NULL)
{
printf("%d\t%s\t%s\t%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",p->num,p->nam,p->col,p->cla,p->math,p->eng,p->clan,p->sum,p->ave);
p=p->next;
}
}
}
void list2(struct node *h)
{
struct node *p;
if(h==NULL)
puts("Empty!");
else
{
p=h;
puts("The student's Information:\nTotal\tNo.\tName\tCollege\tClass\tMath\tEnglish\tC_lan\tAve");
while(p!=NULL)
{
printf("%.2f\t%d\t%s\t%s\t%s\t%.2f\t%.2f\t%.2f\t%.2f\n",p->sum,p->num,p->nam,p->col,p->cla,p->math,p->eng,p->clan,p->ave);
p=p->next;
}
}
}
//creat a new linklist
struct node *creat(void)
{
struct node *h=NULL, *p,*q,*r;
char c='y';
while(c=='y'||c=='Y')
{
puts("Input the student's Information:\nNumber\tName\tCollege\tClass\tMath\tEnglish\tC_language");
p=(struct node *)malloc(L);M++;printf("M:%d\n",M);
scanf("%d%s%s%s%f%f%f",&p->num,&p->nam,&p->col,&p->cla,&p->math,&p->eng,&p->clan,&p->sum,&p->ave);
getchar();
p->next=NULL;
float sum,ave;
sum=p->math + p->eng + p->clan;
ave=sum/3;
p->sum=sum;
p->ave=ave;
if(h==NULL)
h=p;
else
{
q=h;
while((p->num>q->num)&&(q->next!=NULL))
{
r=q;
q=q->next;
}
if(p->num<q->num)
{
if(q==h)
h=p;
else
r->next=p;
p->next=q;
}
else
q->next=p;
}
puts("Continue CREAT or not?(y/n)");
scanf("%c",&c);getchar();
}
return h;
}
//insert information into the created-linklist
struct node *insert(struct node *h)
{
struct node *p,*q,*r;
char c='y';
while(c=='y'||c=='Y')
{
puts("Insert Information:\nNumber\tName\tCollege\tClass\tMath\tEnglish\tC_language");
p=(struct node *)malloc(L);M++;printf("M:%d\n",M);
scanf("%d%s%s%s%f%f%f",&p->num,&p->nam,&p->col,&p->cla,&p->math,&p->eng,&p->clan,&p->sum,&p->ave);
getchar();
p->next=NULL;
float sum,ave;
sum=p->math + p->eng + p->clan;
ave=sum/3;
p->sum=sum;
p->ave=ave;
if(h==NULL)
h=p;
else
{
q=h;
while((p->num>q->num)&&(q->next!=NULL))
{
r=q;
q=q->next;
}
if(p->num<q->num)
{
if(q==h)
h=p;
else
r->next=p;
p->next=q;
}
else
q->next=p;
}
puts("Continue INSERT or not?(y/n)");
scanf("%c",&c);getchar();
}
return h;
}
//delete the information
struct node *del(struct node *h,int n)
{
struct node *p,*q;
p=h;
while((p->num!=n)&&(p!=NULL))
{
q=p;
p=p->next;
}
if(p->num==n)
{
if(p==h)
h=p->next;
else
q->next=p->next;
free(p);
M--;printf("M:%d\n",M);
puts("Delete!");
}
else
puts("Can't Delete!");
return h;
}
//modify
struct node *modify(struct node *h)
{
int n;
puts("Which student's information do you want to modify?\nInput the No.:");
scanf("%d",&n);getchar();
h=del(h,n);
h=insert(h);
return h;
}
//search the information by number
struct node *sea_num(struct node *h)
{
int n;
puts("Input the Student's Number:");
scanf("%d",&n);getchar();
struct node *p;
p=h;
while((p->num!=n)&&(p->next!=NULL))
p=p->next;
if(p->num==n)
{
puts("\nNo.\tName\tCollege\tClass\tMath\tEnglish\tC_lan\tTotal\tAve");
printf("%d\t%s\t%s\t%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",p->num,p->nam,p->col,p->cla,p->math,p->eng,p->clan,p->sum,p->ave);
}
else
puts("Error!\nCan't Find the Student's Number!");
return h;
}
//search the information by name
struct node *sea_nam(struct node *h)
{
struct node *p;
char nam[N];
puts("Input the Student's Name:");
scanf("%s",nam);getchar();
p=h;
while((strcmp(p->nam,nam)!=0)&&(p->next!=NULL))
p=p->next;
if(strcmp(p->nam,nam)==0)
{
puts("\nNo.\tName\tCollege\tClass\tMath\tEnglish\tC_lan\tTotal\tAve");
printf("%d\t%s\t%s\t%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",p->num,p->nam,p->col,p->cla,p->math,p->eng,p->clan,p->sum,p->ave);
}
else
puts("Error!\nCan't Find the Student's Name!");
return h;
}
//search the information by college
struct node *sea_col(struct node *h)
{
struct node *p;
char nam[N];
puts("Input the Student's College:");
scanf("%s",nam);getchar();
p=h;
while((strcmp(p->nam,nam)!=0)&&(p->next!=NULL))
p=p->next;
if(strcmp(p->col,nam)==0)
{
puts("\nNo.\tName\tCollege\tClass\tMath\tEnglish\tC_lan\tTotal\tAve");
printf("%d\t%s\t%s\t%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",p->num,p->nam,p->col,p->cla,p->math,p->eng,p->clan,p->sum,p->ave);
}
else
puts("Error!\nCan't Find the Student's College!");
return h;
}
//search the information by class
struct node *sea_cla(struct node *h)
{
struct node *p;
char nam[N];
puts("Input the Student's Class:");
scanf("%s",nam);getchar();
p=h;
while((strcmp(p->cla,nam)!=0)&&(p->next!=NULL))
p=p->next;
if(strcmp(p->nam,nam)==0)
{
puts("\nNo.\tName\tCollege\tClass\tMath\tEnglish\tC_lan\tTotal\tAve");
printf("%d\t%s\t%s\t%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",p->num,p->nam,p->col,p->cla,p->math,p->eng,p->clan,p->sum,p->ave);
}
else
puts("Error!\nCan't Find the Student's Class!");
return h;
}
//search_display
struct node *sea_dis(struct node *h)
{
int k;
int c='y';
puts("******SEARCH******");
puts("Choose the student's information to search:");
puts("\n\t\t\t1.NUMBER\t2.NAME\n\t\t\t3.COLLEGE\t4.CLASS\n");
puts("Input the Item No. first:");
scanf("%d",&k);getchar();
switch(k)
{
case 1:
{
puts("******NUMBER SEARCH******");
while(c=='y'||c=='Y')
{
h=sea_num(h);
puts("Continue NUMBER SEARCH or not?(y/n)");
scanf("%c",&c);getchar();
}
}break;
case 2:
{
puts("******NAME SEARCH******");
while(c=='y'||c=='Y')
{
h=sea_nam(h);
puts("Continue NAME SEARCH or not?(y/n)");
scanf("%c",&c);getchar();
}
};break;
case 3:
{
puts("******COLLEGE SEARCH******");
while(c=='y'||c=='Y')
{
h=sea_col(h);
puts("Continue COLLEGE SEARCH or not?(y/n)");
scanf("%c",&c);getchar();
}
}break;
case 4:{
puts("******CLASS SEARCH******");
while(c=='y'||c=='Y')
{
h=sea_cla(h);
puts("Continue CLASS SEARCH or not?(y/n)");
scanf("%c",&c);getchar();
}
}break;
default:puts("Error!");
}
return h;
}
//statistics of the amount of average
void sta_ave(struct node *h)
{
struct node *p;int i;
int a[5]={0};
p=h;
while(p!=NULL)
{
if((p->ave>=90)&&(p->ave<=100))
a[0]++;
if((p->ave>=80)&&(p->ave<90))
a[1]++;
if((p->ave>=70)&&(p->ave<80))
a[2]++;
if((p->ave>=60)&&(p->ave<70))
a[3]++;
if((p->ave>=0)&&(p->ave<60))
a[4]++;
p=p->next;
}
puts("Tips:\nA:90-100\tB:80-89\tC:70-79\tD:60-69\tE:Failed\n");
int c=65;
for(i=0;i<5;i++,c++)
printf("\t%c:%d\n",c,a[i]);
}
//find the highest score student
void sta_sco(struct node *h)
{
struct node *p;
p=h;
float max=0;
while(p!=NULL)
{
if(p->sum>max)
max=p->sum;
p=p->next;
}
p=h;
puts("The HighestScore-Student's Information are as follows:");
puts("\nNo.\tName\tCollege\tClass\tMath\tEnglish\tC_lan\tTotal\tAve");
while(p!=NULL)
{
if(p->sum==max)
printf("%d\t%s\t%s\t%s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",p->num,p->nam,p->col,p->cla,p->math,p->eng,p->clan,p->sum,p->ave);
p=p->next;
}
}
//statistics
void sta_fai(struct node *h)
{
struct node *p;
int a[3]={0},c=65;
puts("Tips:\nA:Math\tB:English\tC:C-language");
p=h;
while(p!=NULL)
{
if(p->math<60.0)
a[0]++;
p=p->next;
}
printf("The RATE of %c-Failer:%.2f%c\n",c,(a[0]/(float)M)*100,37);
p=h;
while(p!=NULL)
展开阅读全文