任务:
设计一个学生成绩排名系统。
实现功能:
1) 具备对成绩的管理功能(添加、删除、排序)
2) 具备对成绩的统计功能(最高分,最低分,平均分,及格率等)
3) 具备按学号、姓名、或课程名查询成绩的功能。
4)学生成绩应该保存在文件中。
备注:成绩记录以下信息:班级,学号,姓名,课程名,成绩(百分制)。可以用能表示学生成绩的结构体数组存储数据。
概要设计
一、设计思路
1.根据题目要求成绩记录以下信息:班级,学号,姓名,课程名,成绩。可以把这些信息设为结构体成员,用结构体数组来存放45个学生的信息,并且为方便输入信息可以定义一个全局变量N。
2.将系统功能分为五大模块:读取,管理,统计,查询和保存。另外在程序中需要增加读取文件信息的功能,以保证可以正确执行四大模块功能。
3.细化具体系统的功能,并用函数的嵌套调用来实现
- 将管理功能细化分为增添、删除和排序。
- 2. 将统计功能分为求最大值、最小值、平均值和及格率。
- 将查询功能分按学号、姓名、班级查询。
4.函数调用方法:用switch语句实现多分支选择结构。在主函数中用switch语句调用四大模块函数,在前三大模块函数中用switch语句调用细化的功能函数。各个模块的函数功能相互独立,不会影响别的函数的功能。
5.程序界面设计:在三大主函数中加入printf语句具体提示用户具体功能信息,以保证用户在使用时能逐步实现具体的系统功能。
二、学生成绩系统结构图
详细设计
一、声明结构体和全局变量
①:首先声明结构体,然后定义结构体数组,数组的每一个元素都包含结构体中的所有成员即学号、姓名、班级、课程名以及分数。
②:为节省输入信息的时间,定义一个全局变量N=20。(同时为保证更接近信息真实情况,数字不能过小)。
代码如下:
struct Student
{
int num;
char name[20];
int clas;
char course[10];
float score;
}stu[45];
int N=20;
二、主函数模块
- 先声明管理、统计、查询、读取和保存函数。
- 在声明函数之后,紧接着调用读取信息函数,读取文本文件中的学生信息。
- 输入提示信息,以保证程序在运行时,用户能够方便快速的进行操作。
- 4.用switch选择语句进行对输入的命令进行判断,并且调用相应的函数。
代码如下:
int main()
{
void manage(struct Student stu[]); //声明管理信息函数
void count(struct Student stu[]); //声明统计信息函数
void search(struct Student *p); //声明查找信息函数
void save(); //声明保存信息函数
void read(); //声明读入信息函数
read(); //调用读入信息函数(此处需特别注意read函数的位置:只有先读入文本文件信息,才能进行后续操作)
printf("*****************************学生成绩管理系统***********************************");
printf("* *");
printf("* 管理学生信息(请输入1) 统计学生信息(请输入2) *");
printf("* 查询学生信息(请输入3) 保存学生信息(请输入4) *");
printf("* *");
printf("********************************************************************************");
printf("请输入功能选项(1-manage/2-count/3-search/4-save):\n");
int order;
scanf("%d",&order);
switch(order) //用switch选择结构来调用四个不同的函数
{
case 1:
manage(stu);break;
case 2:
count(stu);break;
case 3:
search(stu);break;
case 4:
save();break;
}
return 0;
}
三、读取信息函数模块
首先定义一个文件指针变量
用fopen函数,以“r”的方式打开一个文本文件(在此之前需建立好一个文本文件),并判断是否能正常打开。
用for循环来以格式化的方式读取磁盘文件中的信息。
- 关闭所打开的文件。
- 代码如下:
void read() //定义读入函数(注意read函数在主函数中调用的位置) { FILE *fp; int i; if((fp=fopen("student.txt","r"))==NULL) //r表示为了输入数据打开一个文本文件 { printf("cannot open the file!\n"); exit(0); } for(i=0;i<N;i++) { fscanf(fp,"%d %s %d %s %f",&stu[i].num,stu[i].name,&stu[i].clas,stu[i].course,&stu[i].score); } //用格式化的方式读取磁盘文件中的信息 fclose(fp); }
四、管理信息函数模块
-
将管理信息模块分为增加、删除和排序三个功能。用switch选择语句进行判断用户的功能选择,进而调用这三个函数。
代码如下:
void manage(struct Student stu[]) //定义管理函数 { printf("**********************欢迎来到学生成绩系统管理界面******************************"); int choice; printf("请输入功能选项(1-add/2-delete/3-sort):\n"); scanf("%d",&choice); switch(choice) { case 1: add();break; //当选择为1时,调用增添函数 case 2: delet();break; //当选择为2时,调用删除函数 case 3: sort();break; //当选择为3时,调用排序函数 } }
五、统计信息函数模块
-
将统计模块分为四个小功能:求最大值、最小值、平均值和及格率。通过switch选择结构来实现用户对不同功能的选择。程序上则是对不同函数的调用。
代码如下:
void count(struct Student stu[]) //定义统计函数 { printf("************************欢迎来到学生系统统计界面********************************"); int choice; printf("请输入功能选项(1-max/2-min/3-average/4-pass_rate):\n"); scanf("%d",&choice); switch(choice) { case 1: max();break; //当选择为1时,调用max函数 case 2: min();break; //当选择为2时,调用min函数 case 3: average();break; //当选择为3时,调用average函数 case 4: pass_rate();break; } }
-
六、查询函数信息模块
-
将查询模块分为三个功能实现:按学号、姓名和班级三种不同的路径实现对成绩的查询。
用switch语句对用户输入的命令选择,实现对不同函数的调用和实现不同的功能。
void search(struct Student stu[]) //定义查询函数 { printf("**********************欢迎来到学生成绩系统查询界面******************************"); int choice; printf("请输入功能选项(1-num_search/2-name_search/3-clas_search):\n"); scanf("%d",&choice); switch(choice) { case 1: num_search();break; case 2: name_search();break; case 3: clas_search();break; } }
课程设计成果
一、程序源代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct Student
{
int num;
char name[20];
int clas;
char course[10];
float score;
}stu[45]; //定义结构体数组,用来存放每一个学生的信息
int N=20; //定义一个全局变量N,用来控制需要输入的学生个数,此处为以后输入节省时间,设为20
int main()
{
void manage(struct Student stu[]); //声明管理信息函数
void count(struct Student stu[]); //声明统计信息函数
void search(struct Student stu[]); //声明查找信息函数
void save(); //声明保存信息函数
void read(); //声明读入信息函数
read(); //调用读入信息函数(此处需特别注意read函数的位置:只有先读入信息,才能进行后续操作)
printf("*****************************学生成绩管理系统***********************************");
printf("* *");
printf("* 管理学生信息(请输入1) 统计学生信息(请输入2) *");
printf("* 查询学生信息(请输入3) 保存学生信息(请输入4) *");
printf("* *");
printf("********************************************************************************");
printf("请输入功能选项(1-manage/2-count/3-search/4-save):\n");
int order;
scanf("%d",&order);
switch(order) //用switch选择结构来调用四个不同的函数
{
case 1:
manage(stu);break;
case 2:
count(stu);break;
case 3:
search(stu);break;
case 4:
save();break;
}
return 0;
}
//以下为读取保存函数
void read() //定义读入函数(注意read函数在主函数中调用的位置)
{
FILE *fp;
int i;
if((fp=fopen("student.txt","r"))==NULL) //r表示为了输入数据打开一个文本文件
{
printf("cannot open the file!\n");
exit(0);
}
for(i=0;i<N;i++)
{
fscanf(fp,"%d %s %d %s %f",&stu[i].num,stu[i].name,&stu[i].clas,stu[i].course,&stu[i].score);
} //用格式化的方式读取磁盘文件中的信息
fclose(fp);
}
void save() //定义保存函数
{
FILE *fp; //定义文件指针表变量fp
int i;
if((fp=fopen("student.txt","w"))==NULL) //w表示为了输出数据,打开了一个文本文件
{
printf("cannot open the file!\n");
exit(0);
}
for(i=0;i<N;i++)
{
fprintf(fp,"%d %s %d %s %5.1f",stu[i].num,stu[i].name,stu[i].clas,stu[i].course,stu[i].score);
} //将变量中的学生信息按预定的格式保存到文件后关闭文件
fclose(fp);
printf("已将学生的信息保存在文件中!\n");
}
void add(); //对以下函数做出声明(写在所有函数前面的外部声明在整个文件范围中有效)
void delet();
void sort();
void max();
void min();
void average();
void pass_rate();
void num_search();
void name_search();
void clas_search();
//以下为管理函数
void manage(struct Student stu[]) //定义管理函数
{
printf("**********************欢迎来到学生成绩系统管理界面******************************");
int choice;
printf("请输入功能选项(1-add/2-delete/3-sort):\n");
scanf("%d",&choice);
switch(choice)
{
case 1:
add();break; //当选择为1时,调用增添函数
case 2:
delet();break; //当选择为2时,调用删除函数
case 3:
sort();break; //当选择为3时,调用排序函数
}
}
void add() //定义添加函数
{
char ch;
FILE *fp;
if((fp=fopen("student.txt","a"))==NULL) //以追加的方式在文本文件的末尾添加数据
{
printf("cannot open the file!\n");
exit(0);
}
printf("\n请输入要增加的同学的信息(学号、姓名、班级、课程、成绩(以#结束)):\n");
ch=getchar(); //接收从键盘输入的第一个字符
while(ch!='#') //当输入‘#’结束循环
{
fputc(ch,fp); //向磁盘文件输出一个字符
putchar(ch); //将输出的字符显示在屏幕上
ch=getchar(); //再接收从键盘输入的一个字符
}
fclose(fp);
putchar(10); //向屏幕输出一个换行符
printf("信息已经成功添加!");
putchar(10);
}
void delet() //定义删除函数
{
int i,number,k=-1;
printf("请输入要删除同学的学号:\n");
scanf("%d",&number);
for(i=0;i<N;i++) //利用循环判断学号和文件中的学号是否相同
{
if(stu[i].num==number) //如果有相匹配的学号用k将i值记录下来
{
k=i;
}
}
if(k<0)
printf("输入的学号有误!请重新输入!\n");
else
{
for(i=k;i<N;i++)
stu[i]=stu[i+1]; //删除数据
printf("删除成功!\n");
save(); //保存删除数据以后的信息
}
}
void sort() //选择法排序(从小到大排序)
{
int i,j,k;
struct Student t; //设置一个结构体交换变量t
for(i=0;i<N-1;i++) //利用循环进行排序
{
k=i;
for(j=i+1;j<N;j++)
{
if(stu[k].score>stu[j].score)
k=j;
}
if(k!=i)
{
t=stu[i]; //将学生的信息进行交换
stu[i]=stu[k];
stu[k]=t;
}
}
printf("********************************排序的结果为:***********************************");
printf("\n学生成绩为(由小到大排列):\n");
printf(" 学号 姓名 班级 课程 分数\n");
for(i=0;i<N;i++) //利用循环输出排序后的信息
{
printf("%3d %3s %3d %5s %5.1f\n",stu[i].num,stu[i].name,stu[i].clas,stu[i].course,stu[i].score);
}
}
//以下为统计函数
void count(struct Student stu[]) //定义统计函数
{
printf("************************欢迎来到学生系统统计界面********************************");
int choice;
printf("请输入功能选项(1-max/2-min/3-average/4-pass_rate):\n");
scanf("%d",&choice);
switch(choice)
{
case 1:
max();break; //当选择为1时,调用max函数
case 2:
min();break; //当选择为2时,调用min函数
case 3:
average();break; //当选择为3时,调用average函数
case 4:
pass_rate();break;
}
}
void max() //定义取最大值函数
{
int i,k;
for(i=0,k=0;i<N;i++)
{
if(stu[k].score<stu[i].score)
k=i;
}
printf("*****************************统计最大值的结果为:********************************");
printf("获得最高分数的学生的信息为:\n");
printf(" 学号 姓名 班级 课程 分数\n");
printf("%3d %3s %3d %5s %5.2f\n",stu[k].num,stu[k].name,stu[k].clas,stu[k].course,stu[k].score);
}
void min() //定义取最小值函数
{
int i,k;
for(i=0,k=0;i<N;i++)
{
if(stu[k].score>stu[i].score)
k=i;
}
printf("******************************统计最小值的结果为:*******************************");
printf("获得最低分数的学生的信息为:\n");
printf(" 学号 姓名 班级 课程 分数\n");
printf("%3d %3s %3d %5s %5.2f\n",stu[k].num,stu[k].name,stu[k].clas,stu[k].course,stu[k].score);
}
void average() //定义取平均值函数
{
float aver,sum=0;
int i;
for(i=0;i<N;i++)
{
sum+=stu[i].score;
}
aver=sum/N;
printf("******************************统计平均值的结果为:*******************************");
printf("所有学生的成绩的平均值为:%5.2f\n",aver);
printf("\n");
}
void pass_rate() //定义通过率函数
{
int i,n=0;
float rate;
for(i=0;i<N;i++)
{
if(stu[i].score>=60) //如果输入的学生成绩大于60,则n自增1
n++;
}
rate=(float)n/N; //求及格率
printf("***************************统计及格率的结果为:**********************************");
printf("这门课程的及格率为:%-5.2f%%\n",rate*100); //以百分制形式输出及格率
}
//以下为查询函数
void search(struct Student stu[]) //定义查询函数
{
printf("**********************欢迎来到学生成绩系统查询界面******************************");
int choice;
printf("请输入功能选项(1-num_search/2-name_search/3-clas_search):\n");
scanf("%d",&choice);
switch(choice)
{
case 1:
num_search();break;
case 2:
name_search();break;
case 3:
clas_search();break;
}
}
void num_search() //定义按学号查询函数
{
int n;
int i;
printf("请输入你想要查询的学生的学号:\n");
scanf("%d",&n);
while(n>=2016120&&n<=2016139) //用while语句判断输入的学号是否在范围内
{
printf("*****************************按学号查询的结果为:********************************");
printf(" 学号 姓名 班级 课程 分数\n");
for(i=0;i<N;i++)
{
if(stu[i].num==n)
{
printf("%3d %3s %3d %5s %5.2f\n",stu[i].num,stu[i].name,stu[i].clas,stu[i].course,stu[i].score);
}
}
break;
}
while(n<2016120||n>2016139)
{
printf("您输入的学号有误!请重新输入!\n");
break;
}
}
void name_search() //定义按姓名查询函数
{
char name[20];
int i;
printf("请输入你想要查询的学生的姓名:\n");
scanf("%s",name); //name就本身为数组名,值为地址,因此此处不需要再加&符号
printf("*****************************按姓名查询的结果为:********************************");
printf("学号 姓名 班级 课程 分数\n");
for(i=0;i<N;i++)
{
if(strcmp(name,stu[i].name)==0)
{
printf("%3d %3s %3d %5s %5.2f\n",stu[i].num,stu[i].name,stu[i].clas,stu[i].course,stu[i].score);
}
}
}
void clas_search() //定义按班级查询函数
{
int c;
int m=0,i;
printf("请输入你想查询学生信息的所在班级:\n");
scanf("%d",&c);
while(c>=001&&c<=020)
{
printf("*****************************按班级查询的结果为:********************************");
printf(" 学号 姓名 班级 课程 分数\n");
for(i=0;i<N;i++)
{
if(stu[i].clas==c)
{
printf("%3d %3s %3d %5s %5.2f\n",stu[i].num,stu[i].name,stu[i].clas,stu[i].course,stu[i].score);
}
}
break;
}
while(c<001||c>020)
{
printf("您输入的班级有误!请重新输入!\n");
break;
}
}
二、设计心得
- 设计过程中出现的错误及解决方法。
- :在定义结构体变量成员——学号和班级时,定义其为为整型,不需要定义为数组,字符型的数据——姓名和课程可以设为数组。在比较信息中的学号和输入的学号是否相同,只需用逻辑等即可,不需要用字符串比较函数。
- :在使用fscanf函数时,输入项表列中的课程和姓名两项被定义为数组,数组名值即为地址,因此其前不需要加&符号。
- :switch语句后面的表达式,其值的类型应为整数类型(包括字符型)。
- :在运用文件知识向增加学生信息时,应该在while循坏最后写ch=getchar(),继续接收从键盘输入的字符。
- :在删除函数最后要调用保存函数,保存删除过后学生信息的文本文件。
- :计算及格率时,rate为浮点型数据,而n和N都为整型数据,因此应在之前加float。
- :while循环最后要加入break语句,在找到匹配信息后及时结束循环。
- :主函数中read函数的调用应放在函数声明之后,做到先读取文件中的信息,才能进行后面的操作。
- 个人总结
- :在设计一个程序时不要急着去写代码,最好能先写出思路及大纲,将问题分解为一些小步骤去解决,逐步完成程序设计会更加方便。
- :在设计代码时应该要在写出一点及时运行一下,检查有没有语法错误或者不能实现具体功能的问题。以免在写完之后错误太多不便于更改或者在没有语法错误的情况下运行不了,并且找不到错误的具体位置。
- :在设计程序时,及时添加详细的备注,以免以后忘记设计的原因。
- :设计一个系统,在设计界面时,应该能给用户直观简洁的印象。要有必要的提示信息,让用户在使用时知道如何进行下一步操作。输出的信息也要直观明了。
版权声明:本文为博主作者:NBITer原创文章,版权归属原作者,如果侵权,请联系我们删除!