学生成绩管理系统
1. 问题描述
题目:学生成绩管理程序
要求:本程序用于教学单位(院/系)的学生成绩管理。要求程序能够实现学生信息录入(可以实现增加、删除、修改学生的基本信息)、单科学习成绩的录入;班级内单科成绩排名;成绩查询:查询某个学生的各科成绩、统计所有不及格科目超过2科的学生名单。
2. 概要设计
2.1 系统主要执行逻辑
2.2 函数调用关系
3. 函数实现
3.1 头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
3.2 核心数据结构设计
//学生信息
struct student
{
char number[20];
char name[50];
double math;
double english;
double cs;
};
//结点信息
struct node
{
struct student data;
struct node *next;
};
3.3 密码登录
“程序用于教学单位(院/系)的学生成绩管理”,则需要使用权限即密码来保障系统信息安全。
用户根据提示输入密码,输入正确则进入系统,输入错误则报错并退出系统。(输入的密码用*号隐藏)
//登录密码
int Login()
{
char key[20] = "123";
char password[20];
char input;
int i = 0;
printf("\t\t\t ----------------------------------\n");
printf("\t\t\t | 欢迎使用学生成绩管理系统 |\n");
printf("\t\t\t ----------------------------------\n");
printf("\n请输入管理员密码:");
while ((input = _getch()) != '\r')
{
if (input == '\b')
{
i--;
printf("\b \b");
}
else
{
password[i++] = input;
printf("*");
}
}
if (strcmp(key, password) == 0)
{
return 1;
}
else
{
return 0;
}
}
3.4 界面菜单
用菜单展示功能选项,以便于用户的选择与操作。
根据菜单提示,用户可输入数字来选择相应功能选项,完成相应操作。
若输入非菜单中数字选项,则报错,进行重新选择。
//界面菜单
void Menu()
{
printf("\t\t\t+==============================================+\n");
printf("\t\t\t| |\n");
printf("\t\t\t| 欢迎来到学生成绩管理系统 |\n");
printf("\t\t\t| |\n");
printf("\t\t\t|==============================================|\n");
printf("\t\t\t| 请选择功能选项 |\n");
printf("\t\t\t|----------------------------------------------|\n");
printf("\t\t\t| |\n");
printf("\t\t\t| 1.录入学生信息 |\n");
printf("\t\t\t| 2.增加学生信息 |\n");
printf("\t\t\t| 3.删除学生信息 |\n");
printf("\t\t\t| 4.修改学生信息 |\n");
printf("\t\t\t| 5.显示学生信息 |\n");
printf("\t\t\t| 6.查询单科成绩排名 |\n");
printf("\t\t\t| 7.查询某学生各科成绩 |\n");
printf("\t\t\t| 8.不及格科目超过2科的学生名单 |\n");
printf("\t\t\t| 9.退出系统 |\n");
printf("\t\t\t| |\n");
printf("\t\t\t+==============================================+\n");
printf("\n");
}
3.5 保存学生信息
//保存学生信息
void SaveFile(struct node* L)
{
FILE* file = fopen("Student.sys" , "w");
if (file == NULL)
{
printf("\t* 打开文件失败 *\n");
return;
}
struct node* p = L->next;
while (p != NULL)
{
if (fwrite(&p->data, sizeof(struct student), 1, file) != 1)
{
printf("\t* 保存%s的信息时出现错误 *\n", p->data.name);
}
p = p->next;
}
fclose(file);
}
3.6 读取学生信息
//读取学生信息
void ReadFile(struct node* L)
{
FILE* file = fopen("Student.sys" , "r");
if (file == NULL)
{
printf("\t\t* 未找到学生文件,跳过读取 *\n");
return;
}
struct node* rear = L;
struct node* Tmpcell;
Tmpcell = (struct node*)malloc(sizeof(struct node));
Tmpcell->next = NULL;
while (fread(&Tmpcell->data, sizeof(struct student), 1, file) == 1)
{
rear->next = Tmpcell;
rear = Tmpcell;
Tmpcell = (struct node*)malloc(sizeof(struct node));
Tmpcell->next = NULL;
}
free(Tmpcell);
fclose(file);
printf("\t\t\t* 已读取文件 *\n");
}
3.7 录入学生信息
用户根据提示选择以下2种功能。
(1)录入学生基本信息
用户根据提示进行相关操作。
输入“1”则进行操作,根据提示输入数字,(若输入非数字,则报错并结束此功能),接着依次根据系统提示录入相应基本信息;
输入“0”则退出操作; 若输入其它,则报错,进行重新输入。
(2)录入学生单科成绩
用户根据提示进行相关操作。
输入“2”则进行操作,(若系统中无录入基本信息,则报错重新进行选择)接着根据系统提示,选择所要录入科目进行录入成绩(若输入超过正常成绩数值范围则报错);
输入“0”则退出操作; 若输入其它,则报错,进行重新输入。
//录入学生信息
void Input(struct node* L)
{
char choice;
while (choice != '0')
{
printf("录入基本信息请按1,录入单科成绩请按2,退出请按0\n\n");
choice = _getch();
switch (choice)
{
case '1':
Basic(L);
break;
case '2':
Score(L);
break;
case '0':
printf("* 已退出 *\n");
system("pause");
system("cls");
return;
default:
printf("* 输入有误,请重新输入 *\n");
break;
}
}
}
//录入学生基本信息
void Basic(struct node* L)
{
int num;
int i = 0;
char choice;
char input[20];
struct node* rear = L;
struct node* Tmpcell;
printf("需录入多少个学生信息\n");
scanf("%s", input);
while (input[i] != '\0')
{
if ((input[i]<'0') || (input[i]>'9'))
{
printf("* 输入有误,请输入数字 *\n");
system("pause");
system("cls");
return;
}
i++;
}
num = atoi(input);
printf("\n您将输入%d个学生信息\n\n", num);
for (i=0; i<num; i++)
{
Tmpcell = (struct node*)malloc(sizeof(struct node));
Tmpcell->next = NULL;
printf("请输入学生的学号,姓名:\n");
scanf("%s", Tmpcell->data.number);
scanf("%s", Tmpcell->data.name);
Tmpcell->data.math = 0;
Tmpcell->data.english = 0;
Tmpcell->data.cs = 0;
rear->next = Tmpcell;
rear = Tmpcell;
}
SaveFile(L);
printf("\n* 已完成 *\n");
return;
}
//录入学生单科成绩信息
void Score(struct node* L)
{
int num;
int i = 0;
char choice;
char input[20];
struct node* p = L;
if (p->next == NULL)
{
printf("* 无基本信息录入,请先录入学生基本信息 *\n\n");
return;
}
printf("请选择你所要输入的成绩,数学成绩请按1,英语成绩请按2,专业成绩请按3,退出请按0\n\n");
while (choice != '0')
{
choice = _getch();
switch (choice)
{
case '1':
p = L;
while (p->next != NULL)
{
printf("请输入%s %s的数学成绩:\n", p->next->data.number, p->next->data.name);
scanf("%lf", &p->next->data.math);
if ((p->next->data.math<0) || (p->next->data.math>100))
{
printf("* 数学成绩输入范围错误,请重新输入 *\n");
return;
}
p = p->next;
}
break;
case '2':
p = L;
while (p->next != NULL)
{
printf("请输入%s %s的英语成绩:\n", p->next->data.number, p->next->data.name);
scanf("%lf", &p->next->data.english);
if ((p->next->data.english<0) || (p->next->data.english>100))
{
printf("* 英语成绩输入范围错误,请重新输入 *\n");
return;
}
p = p->next;
}
break;
case '3':
p = L;
while (p->next != NULL)
{
printf("请输入%s %s的专业成绩:\n", p->next->data.number, p->next->data.name);
scanf("%lf", &p->next->data.cs);
if ((p->next->data.cs<0) || (p->next->data.cs>100))
{
printf("* 专业成绩输入范围错误,请重新输入 *\n");
return;
}
p = p->next;
}
break;
case '0':
SaveFile(L);
printf("\n* 已完成 *\n");
return;
default:
printf("* 输入有误,请重新输入 *\n");
break;
}
}
}
3.8 增加学生信息
用户根据提示进行相关操作。
输入“1”则进行操作,依次根据系统提示录入相应信息和成绩(若输入超过正常成绩数值范围则报错),然后可进行选择决定是否继续执行此操作,如此循环;
输入“0”则退出操作; 若输入其它,则报错,进行重新输入。
//增加学生信息
void Add(struct node* L)
{
struct node* rear = L;
struct node* Tmpcell;
char choice;
while (rear->next != NULL)
{
rear = rear->next;
}
printf("是否增加学生信息? 是请按1,否请按0\n\n");
while (choice != '0')
{
choice = _getch();
if (choice == '1')
{
Tmpcell = (struct node*)malloc(sizeof(struct node));
Tmpcell->next = NULL;
printf("请输入学生的学号,姓名,数学成绩,英语成绩,专业成绩:\n");
scanf("%s", Tmpcell->data.number);
scanf("%s", Tmpcell->data.name);
scanf("%lf", &Tmpcell->data.math);
if ((Tmpcell->data.math<0) || (Tmpcell->data.math>100))
{
printf("* 数学成绩输入范围错误,请重新输入 *\n");
return;
}
scanf("%lf", &Tmpcell->data.english);
if ((Tmpcell->data.english<0) || (Tmpcell->data.english>100))
{
printf("* 英语成绩输入范围错误,请重新输入 *\n");
return;
}
scanf("%lf", &Tmpcell->data.cs);
if ((Tmpcell->data.cs<0) || (Tmpcell->data.cs>100))
{
printf("* 专业成绩输入范围错误,请重新输入 *\n");
return;
}
rear->next = Tmpcell;
rear = Tmpcell;
}
else if (choice == '0')
{
SaveFile(L);
printf("* 已退出 *\n");
system("pause");
system("cls");
return;
}
else
{
printf("* 输入有误,请重新输入 *\n");
}
printf("\n是否继续增加学生信息? 是请按1,否请按0\n\n");
}
}
3.9 删除学生信息
用户根据提示进行相关操作。输入“1”则进行操作,输入所要删除学生信息的学号,进行删除。
(若无此学号,则报错并结束此功能),然后可进行选择决定是否继续执行此操作,如此循环;
输入“0”则退出操作; 若输入其它,则报错,进行重新输入。
//删除学生信息
void Delete(struct node* L)
{
char id[20];
char choice;
int flag = 0;
struct node* p = L;
struct node* temp;
printf("是否删除学生信息? 是请按1,否请按0\n\n");
while (choice != '0')
{
choice = _getch();
if (choice == '1')
{
printf("请输入所要删除学生信息的学号:\n");
scanf("%s", id);
p = L;
flag = 0;
while (p->next != NULL)
{
if (strcmp(id, p->next->data.number) == 0)
{
temp = p->next;
p->next = p->next->next;
free(temp);
flag = 1;
SaveFile(L);
printf("* 已删除学生信息 *\n");
break;
}
p = p->next;
}
if (flag == 0)
{
printf("* 未找到学生信息 *\n");
}
}
else if (choice == '0')
{
printf("* 已退出 *\n");
system("pause");
system("cls");
return;
}
else
{
printf("* 输入有误,请重新输入 *\n");
}
printf("\n是否继续删除学生信息? 是请按1,否请按0\n\n");
}
}
3.10 修改学生信息
用户根据提示进行相关操作。输入“1”则进行操作,输入所要修改学生信息的学号,进行修改,(若无此学号,则报错并结束此功能)。
修改过程中用户根据提示选择所要修改项目,进行修改(若输入超过正常成绩数值范围则报错)或退出。然后可继续进行选择,如此循环;
输入“0”则退出操作; 若输入其它,则报错,进行重新输入。
//修改学生信息
void Modify(struct node* L)
{
char id[20];
char choice;
char option;
struct node* p = L;
printf("是否修改学生信息? 是请按1,否请按0\n\n");
while (option != '0')
{
option = _getch();
if (option == '1')
{
printf("请输入所要修改学生信息的学号:\n");
scanf("%s", id);
while (p->next != NULL)
{
if (strcmp(id, p->next->data.number) == 0)
{
printf("学号:%s\t姓名:%s\t数学成绩:%lf\t英语成绩:%lf\t专业成绩:%lf\n", p->next->data.number, p->next->data.name, p->next->data.math, p->next->data.english, p->next->data.cs);
printf("\n请选择您所要修改的项目:\n学生学号请按1,学生姓名请按2,数学成绩请按3,英语成绩请按4,专业成绩请按5,退出请按0\n\n");
while (choice != '0')
{
choice = _getch();
switch (choice)
{
case '1':
printf("请输入修改后的学生学号:\n");
scanf("%s", p->next->data.number);
break;
case '2':
printf("请输入修改后的学生姓名:\n");
scanf("%s", p->next->data.name);
break;
case '3':
printf("请输入修改后的数学成绩:\n");
scanf("%lf", &p->next->data.math);
if ((p->next->data.math<0) || (p->next->data.math>100))
{
printf("* 数学成绩输入范围错误,请重新输入 *\n");
return;
}
break;
case '4':
printf("请输入修改后的英语成绩:\n");
scanf("%lf", &p->next->data.english);
if ((p->next->data.english<0) || (p->next->data.english>100))
{
printf("* 英语成绩输入范围错误,请重新输入 *\n");
return;
}
break;
case '5':
printf("请输入修改后的专业成绩:\n");
scanf("%lf", &p->next->data.cs);
if ((p->next->data.cs<0) || (p->next->data.cs>100))
{
printf("* 专业成绩输入范围错误,请重新输入 *\n");
return;
}
break;
case '0':
SaveFile(L);
printf("* 已修改信息 *\n");
system("pause");
system("cls");
return;
default:
printf("* 输入有误,请输入正确的选项 *\n");
break;
}
}
}
p = p->next;
}
printf("* 未找到学生信息 *\n");
system("pause");
system("cls");
return;
}
else if (option == '0')
{
printf("* 已退出 *\n");
system("pause");
system("cls");
return;
}
else
{
printf("* 输入错误,请重新输入 *\n\n");
}
}
}
3.11 显示学生信息
显示所有学生的详细信息(包括学生的学号、姓名和各科成绩)。
//显示学生信息
void Show(struct node* L)
{
struct node* p = L->next;
while (p != NULL)
{
printf("学号:%s\t\t姓名:%s\t数学成绩:%lf\t英语成绩:%lf\t专业成绩:%lf\n\n", p->data.number, p->data.name, p->data.math, p->data.english, p->data.cs);
p = p->next;
}
system("pause");
system("cls");
}
3.12 单科成绩排名
显示各科成绩的排名(包括学生的学号、姓名、单科成绩排名和具体成绩)
//封装排名
void Grade(struct node* L)
{
MathGrade(L);
EnglishGrade(L);
CsGrade(L);
system("pause");
system("cls");
}
//数学成绩排序
void MathGrade(struct node* L)
{
struct node* p = NULL;
struct node* q = NULL;
struct student temp;
for (p=L->next; p->next!=NULL; p=p->next)
{
for (q=L->next; q->next!=NULL; q=q->next)
{
if (q->data.math < q->next->data.math)
{
temp = q->data;
q->data = q->next->data;
q->next->data = temp;
}
}
}
ShowMath(L);
}
void ShowMath(struct node* L)
{
struct node* p = L->next;
int i = 1;
printf("\t\t* 数学成绩排名 *\n\n");
printf("排名\t学号\t\t姓名\t\t成绩\n");
printf("-------------------------------------------------\n");
while (p != NULL)
{
printf("%d\t%s\t\t%s\t\t%lf\n", i, p->data.number, p->data.name, p->data.math);
i++;
p = p->next;
}
}
//英语成绩排序
void EnglishGrade(struct node* L)
{
struct node* p = NULL;
struct node* q = NULL;
struct student temp;
for (p=L->next; p->next!=NULL; p=p->next)
{
for (q=L->next; q->next!=NULL; q=q->next)
{
if (q->data.english < q->next->data.english)
{
temp = q->data;
q->data = q->next->data;
q->next->data = temp;
}
}
}
ShowEnglish(L);
}
void ShowEnglish(struct node* L)
{
struct node* p = L->next;
int i = 1;
printf("\n\t\t* 英语成绩排名 *\n\n");
printf("排名\t学号\t\t姓名\t\t成绩\n");
printf("-------------------------------------------------\n");
while (p != NULL)
{
printf("%d\t%s\t\t%s\t\t%lf\n", i, p->data.number, p->data.name, p->data.english);
i++;
p = p->next;
}
}
//专业成绩排序
void CsGrade(struct node* L)
{
struct node* p = NULL;
struct node* q = NULL;
struct student temp;
for (p=L->next; p->next!=NULL; p=p->next)
{
for (q=L->next; q->next!=NULL; q=q->next)
{
if (q->data.cs < q->next->data.cs)
{
temp = q->data;
q->data = q->next->data;
q->next->data = temp;
}
}
}
ShowCs(L);
}
void ShowCs(struct node* L)
{
struct node* p = L->next;
int i = 1;
printf("\n\t\t* 专业成绩排名 *\n\n");
printf("排名\t学号\t\t姓名\t\t成绩\n");
printf("-------------------------------------------------\n");
while (p != NULL)
{
printf("%d\t%s\t\t%s\t\t%lf\n", i, p->data.number, p->data.name, p->data.cs);
i++;
p = p->next;
}
}
3.13 查询某学生各科成绩
用户根据提示输入所要查询学生的学号,进而显示出查询学生的各科成绩。(若无此学号,则报错并退出此功能)。
//查询学生成绩
void Search(struct node* L)
{
struct node* p = L->next;
char id[20];
printf("请输入所要查询学生成绩的学号:\n");
scanf("%s", id);
while (p != NULL)
{
if (strcmp(id, p->data.number) == 0)
{
printf("学号:%s\t姓名:%s\t数学成绩:%lf\t英语成绩:%lf\t专业成绩:%lf\n", p->data.number, p->data.name, p->data.math, p->data.english, p->data.cs);
system("pause");
system("cls");
return;
}
p = p->next;
}
printf("* 未查询到该学生成绩,请重新输入 *\n");
system("pause");
system("cls");
}
3.14 不及格科目超过2科的学生名单
若有不及格科目超过2科学生,则显示不及格名单;若无不及格科目超过2科学生,则显示“无”。
//不及格超过2科学生名单
void Failed(struct node* L)
{
struct node* p = L->next;
int i = 0;
int flag = 0;
printf("* 不及格超过2科学生名单 *\n\n");
while (p != NULL)
{
if (p->data.math < 60)
{
i++;
}
if (p->data.english < 60)
{
i++;
}
if (p->data.cs < 60)
{
i++;
}
if (i >= 2)
{
printf("学号:%s\t姓名:%s\n\n", p->data.number, p->data.name);
flag = 1;
}
i = 0;
p = p->next;
}
if (flag == 0)
{
printf(" * 无!*\n");
}
system("pause");
system("cls");
}
4. 主函数实现
int main(int argc, char** argv)
{
struct node* L;
char choice;
L = (struct node*)malloc(sizeof(struct node));
L->next = NULL;
if (Login())
{
ReadFile(L);
while (choice != '9')
{
Menu();
choice = _getch();
switch (choice)
{
case '1': //录入学生信息
Input(L);
break;
case '2': //增加学生信息
Add(L);
break;
case '3': //删除学生信息
Delete(L);
break;
case '4': //修改学生信息
Modify(L);
break;
case '5': //显示学生信息
Show(L);
break;
case '6': //查询单科成绩排名
Grade(L);
break;
case '7': //查询某学生各科成绩
Search(L);
break;
case '8': //不及格科目超过2科的学生名单
Failed(L);
break;
case '9': //退出系统
system("cls");
printf("* 感谢您的使用,已退出系统 *\n");
exit(0);
default:
printf("* 输入有误,请选择正确的功能选项 *\n");
system("pause");
system("cls");
break;
}
}
}
else
{
printf("\n* 密码错误,请重新输入 *\n");
system("pause");
system("cls");
exit(0);
}
return 0;
}
5. 遇到的问题及解决方法
1、想在输入登录密码过程中用‘ * ’隐藏。采用了循环输入字符到字符数组中的方法,并且判断是否为‘\b’,是则用‘ * ’覆盖,否则用‘* ’覆盖。
2、输入学生个数时,防止用户输入其它出现bug的情况。将原先的整型转换成字符串,循环遍历判断每个字符是否在正常区间,然后用atoi函数将其转换成数字。
3、防止用户无录入基本信息,而录入单科成绩时,无法录入的情况。在录入单科成绩函数中首先判断链表中是否有数据,无则提示无基本信息并退出此操作。
4、防止用户只录入一科成绩,而其他科目未录入,然后进行查询、显示成绩、单科成绩排名等操作时,其它科目成绩出现任意数的情况。在用户录入基本信息时,就将该学生科目成绩赋为0。
5、录入、增加学生成绩时,避免输入正常成绩范围以外的东西。在输入成绩后,就判断是否在正常范围,否则提示输入有误并退出此操作。
6、避免用户在选择功能时,误触进入操作。在每个函数执行前,首先询问用户是否进行操作,用户进行选择退出或执行。
7、输入学号,进行相关操作(查询、删除、修改)时,判断输入学号与链表中学号是否一致。用strcmp函数实现此操作。
8、在输入选项时,避免输入字符有回车残留的情况。用_getch()得以解决。
9、完成操作时,暂停与清屏的实现。用system(“pause”),system(“cls”)解决。
10、多文件与文件读取、存储功能的实现。查询网络得以解决。
6. 程序具体实现
点击下方链接即可 ^ ^