一、引言
1.1 背景
学生管理系统是一种常见的信息管理工具,用于对学生的基本信息、成绩等进行有效管理。本实验设计和实现了一个简单的学生管理系统,使用链表数据结构存储学生信息,通过 C 语言编写各种功能模块。
1.2 目的
熟悉链表数据结构在实际应用中的使用。
掌握结构体的定义和使用。
实践 C 语言基础知识,包括内存管理、文件操作等。
二、设计与实现
2.1 数据结构设计
本系统使用链表存储学生信息,结构体 data 表示学生的基本信息,结构体 Student 表示链表中的节点。
struct data {
int xh; // 学号
char name[10]; // 姓名
short age; // 年龄
char sex[5]; // 性别
float chinese; // 语文成绩
float math; // 数学成绩
float english; // 英语成绩
};
typedef struct Student {
struct data data; // 数据域
struct Student* next; // 指针域
} *QST, ST;
2.2 主要功能实现
添加学生信息:通过 Add_list 函数,实现用户输入学生信息,并通过链表将信息存储。
查询学生信息:通过 Seek_list 函数,实现按学号或姓名查询学生信息的功能。
修改学生信息:通过 Ament_list 函数,实现修改学生信息的功能。
插入学生信息:通过 Insert_list 函数,在指定学生前插入新的学生信息。
显示所有信息:通过 Output_list 函数,将所有学生信息输出到屏幕上。
删除学生信息:通过 Delete_list 函数,实现删除学生信息的功能,可以选择删除全部或者指定学生。
学生成绩排序:通过 Sort_list 函数,实现对学生信息的排序功能,可以选择按总分、平均分、语文成绩、数学成绩或英语成绩排序。
输出不及格学生:通过 DisplayFailingStudents 函数,输出不及格学生的信息。
输出各科目最高分:通过 DisplayMaxScores 函数,输出各科目的最高分。
2.3 菜单设计
通过 Menu 函数,设计了一个简单的用户界面,用户可以通过选择相应的数字来执行不同的功能。
三、实验结果
3.1 功能演示
添加学生信息
//添加学生信息
void Add_list(QST head)
{
QST p=head;
printf("开始添加\n");
while(p->next!=NULL)
{
p=p->next;
}
Linked_list(p);
Ass_list(p);
system("cls");
printf("添加完成\n");
}
查询学生信息
//查询学生信息
void Seek_list(QST head)
{
QST p = head->next;
QST q = head;
while (true)
{
printf("开始查找\n");
printf("请选择查询方式:[1]按学号[2]按姓名[0]退出");
int num;
scanf("%d", &num);
switch (num)
{
case 1:
printf("请输入学生学号:\n");
int stuNum;
scanf("%d", &stuNum);
while (p != NULL)
{
if (p->data.xh == stuNum)
{
system("cls");
printf("学生姓名:%s,学生学号:%d\n", p->data.name, p->data.xh);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
return;
}
p = p->next;
}
if (p)
{
printf("没有查找到数据\n");
return;
}
case 2:
printf("请输入名字:\n");
getchar();
char name[20];
gets(name);
while (q != NULL)
{
if (strcmp(q->data.name, name) == 0)
{
printf("学生姓名:%s,学生学号:%d\n", q->data.name, q->data.xh);
return;
}
q = q->next;
}
if (q == NULL)
{
printf("没有查找到数据\n");
return;
}
case 0:
printf("退出\n");
return;
break;
default:
printf("用户输入有误请重新输入\n");
break;
}
}
}
修改学生信息
//修改学生信息
void Ament_list(QST head)
{
QST p=head;
if(Pd_list(head))
{
printf("修改失败\n");
return;
}
printf("开始修改\n");
printf("你要修改谁的信息(名字):");
char name[10];
getchar();
gets(name);
// 循环找到要修改的学生
while (p->next != NULL) {
p = p->next;
// 如果找到要修改的学生
if (strcmp(p->data.name, name) == 0) {
// 打印修改前的信息
printf("修改前的信息:\n");
printf("学号:%d, 姓名:%s, 年龄:%hd, 性别:%s\n", p->data.xh, p->data.name, p->data.age, p->data.sex);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
// 调用 Fuzhi 函数修改信息,包括新的科目成绩
Fuzhi(p);
// 打印修改后的信息
printf("修改后的信息:\n");
printf("学号:%d, 姓名:%s, 年龄:%hd, 性别:%s\n", p->data.xh, p->data.name, p->data.age, p->data.sex);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
return; // 结束函数,避免继续循环查找
}
}
// 如果循环结束仍未找到要修改的学生
printf("查无此人\n");
}
插入学生信息
//插入函数
void Insert_list(QST head)
{
QST p=head;
if(Pd_list(head))
{
printf("请先添加,再插入\n");
return;
}
char name[10];
getchar();
printf("你要在谁的前面插入(名字):\n");
gets(name);
//找到插入位置
QST q=p;
p=p->next;
while(strcmp(p->data.name,name))
{
if(p->next==NULL)
{
printf("没有找到这个人\n");
return;
}
q=p;
p=p->next;
}
Linked_list(q);
Ass_list(q);
//循环找到尾结点
while(q->next!=NULL)
{
q=q->next;
}
q->next=p;
printf("插入完成\n");
}
显示所有信息
//打印所有信息
void Output_list(QST head)
{
QST p=head;
system("cls");
printf("开始输出\n");
if(Pd_list(p))
{
return;
}
int index=1;
while(p->next!=NULL)
{
p=p->next;
printf("第%d个学生信息:\n",index++);
printf("学号:%d\n",p->data.xh);
printf("姓名:%s\n",p->data.name);
printf("年龄:%d\n",p->data.age);
printf("性别:%s\n",p->data.sex);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
}
printf("输出完毕!\n");
}
删除学生信息
//删除学生信息
void Delete_list(QST head)
{
QST p=head;
if(Pd_list(head))
{
return;
}
printf("开始删除\n");
printf("你想要全部删除[0] 还是单个删除[1]\n");
int num;
scanf("%d",&num);
if(num==0)
{
printf("正在全部删除中......\n");
Empty_list(head);
printf("全部删除成功\n");
}
else if(num==1)
{
printf("请输入你要删除学生的名字:");
char name[10];
getchar();
gets(name);
//被删除结点的前驱结点
QST qjd=p;
//当前要删除的结点
p=p->next;
while(strcmp(p->data.name,name))
{
if(p->next==NULL)
{
printf("没有找到这个人\n");
return;
}
qjd=p;
p=p->next;
}
qjd->next=p->next;
p->next=NULL;
free(p);
printf("删除成功\n");
return;
}
else
{
printf("用户输入错误\n");
}
}
学生成绩排序
//学生成绩排序
void Sort_list(QST head)
{
QST p = head;
printf("开始排序\n");
if (Pd_list(head))
{
return;
}
// 计算链表长度
int len = 0;
QST jd = p;
while (jd->next != NULL)
{
jd = jd->next;
len++;
}
printf("请选择排序方式:[1]总分 [2]平均分 [3]语文成绩 [4]数学成绩 [5]英语成绩 [0]退出");
int sortOption;
scanf("%d", &sortOption);
QST a, b;
for (int i = 1; i < len; i++)
{
a = p->next;
b = a->next;
for (int j = 0; j < len - i; j++)
{
float scoreA, scoreB;
switch (sortOption)
{
case 1:
scoreA = a->data.chinese + a->data.math + a->data.english;
scoreB = b->data.chinese + b->data.math + b->data.english;
break;
case 2:
scoreA = (a->data.chinese + a->data.math + a->data.english)/3.0;
scoreB = (b->data.chinese + b->data.math + b->data.english)/3.0;
break;
case 3:
scoreA = a->data.chinese;
scoreB = b->data.chinese;
break;
case 4:
scoreA = a->data.math;
scoreB = b->data.math;
break;
case 5:
scoreA = a->data.english;
scoreB = b->data.english;
break;
case 0:
printf("退出\n");
return;
break;
default:
printf("用户输入有误请重新输入\n");
return;
}
if (scoreA > scoreB)
{
struct data temp = a->data;
a->data = b->data;
b->data = temp;
}
a = b;
b = b->next;
}
}
printf("排序完成\n");
}
输出不及格学生
// 输出不及格学生
void DisplayFailingStudents(QST head) {
QST p = head->next;
printf("不及格学生信息:\n");
while (p != NULL) {
if (p->data.chinese < 60 || p->data.math < 60 || p->data.english < 60) {
printf("学号:%d, 姓名:%s\n", p->data.xh, p->data.name);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
printf("\n");
}
p = p->next;
}
}
输出各科目最高分
// 输出各科目最高分
void DisplayMaxScores(QST head) {
float maxChinese = 0, maxMath = 0, maxEnglish = 0;
QST p = head->next;
while (p != NULL) {
maxChinese = (p->data.chinese > maxChinese) ? p->data.chinese : maxChinese;
maxMath = (p->data.math > maxMath) ? p->data.math : maxMath;
maxEnglish = (p->data.english > maxEnglish) ? p->data.english : maxEnglish;
p = p->next;
}
printf("各科目最高分:\n");
printf("语文最高分: %.2f\n", maxChinese);
printf("数学最高分: %.2f\n", maxMath);
printf("英语最高分: %.2f\n", maxEnglish);
}
四、结论
通过本实验,我们成功设计并实现了一个简单的学生管理系统,包括了学生信息的增删改查、排序、输出不及格学生和各科目最高分等功能。通过实践,加深了对链表和结构体的理解,提高了对 C 语言的熟练程度
五、完整代码
//学生管理系统
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<string.h>
struct data //数据域
{
int xh;//学号
char name[10];//名字
short age;//年龄
char sex[5];//性别
float chinese; // 语文成绩
float math; // 数学成绩
float english; // 英语成绩
};
//结点
typedef struct Student
{
struct data data;//数据域
struct Student*next;//指针域
}*QST,ST;
//添加学生信息
void Add_list(QST);
//创建结点
void Linked_list(QST);
//赋值
void Ass_list(QST);
//判断链表是否为空
int Pd_list(QST);
//输出所有信息
void Output_list(QST);
//查询学生信息
void Seek_list(QST);
//删除学生信息
void Delete_list(QST);
//回收所有结点
void Empty_list(QST);
//修改数据
void Ament_list(QST);
//赋值函数
void Fuzhi(QST);
//插入函数
void Insert_list(QST);
//学生成绩排序
void Sort_list(QST);
//输出不及格学生
void DisplayFailingStudents(QST head);
// 输出各科目最高分
void DisplayMaxScores(QST head);
//打印菜单函数
void Menu()
{
printf("***********欢迎来到学生管理系统***********\n");
printf("----------1.添加学生信息------------------\n");
printf("----------2.查询学生信息------------------\n");
printf("----------3.修改学生信息------------------\n");
printf("----------4.插入学生信息------------------\n");
printf("----------5.显示所有信息------------------\n");
printf("----------6.删除学生信息------------------\n");
printf("----------7.学生成绩排序------------------\n");
printf("----------8.输出不及格学生 ---------------\n");
printf("----------9.输出各科目最高分--------------\n");
printf("----------10. 清屏 -----------------\n");
printf("----------11. 退出 -----------------\n");
}
int main()
{
//创建头结点
QST head=(QST)malloc(sizeof(ST));
head->next=NULL;
//要求用户输入一个数值 选择功能
int s;
while(true)
{
//打印菜单
Menu();
printf("请输入1~9之间的数:");
scanf("%d",&s);
switch(s)
{
case 1:
Add_list(head);
break;
case 2:
Seek_list(head);
break;
case 3:
Ament_list(head);
break;
case 4:
Insert_list(head);
break;
case 5:
Output_list(head);
break;
case 6:
Delete_list(head);
break;
case 7:
Sort_list(head);
break;
case 8:
DisplayFailingStudents(head);
break;
case 9:
DisplayMaxScores(head);
break;
case 10:
system("cls");
break;
case 11:
Empty_list(head);
return 0;
break;
default:
printf("用户输入有误,请重新输入\n");
break;
}
}
return 0;
}
//创建结点
void Linked_list(QST wjd)
{
QST p=wjd;
printf("开始创建结点\n");
printf("请输入你要保存几个学生信息:");
int num;
scanf("%d",&num);
if(num<=0)
{
printf("输入有误,创建失败\n");
return;
}
for(int i=0;i<num;i++)
{
QST q=(QST)malloc(sizeof(ST));
if(q==NULL)
{
printf("内存不足!初始化失败.\n");
exit(-1);
}
p->next=q;
q->next=NULL;
p=q;
}
printf("创建完成\n");
}
//判断为空
int Pd_list(QST head)
{
if(head->next==NULL)
{
printf("链表为空\n");
return 1;
}
else
{
return 0;
}
}
//赋值
void Ass_list(QST wjd)
{
QST p=wjd;
printf("开始赋值\n");
if(Pd_list(p))
{
return;
}
int index=1;
while(p->next!=NULL)
{
p=p->next;
printf("请输入第%d个学生的信息\n",index++);
Fuzhi(p);
}
printf("赋值成功!\n");
}
//添加学生信息
void Add_list(QST head)
{
QST p=head;
printf("开始添加\n");
while(p->next!=NULL)
{
p=p->next;
}
Linked_list(p);
Ass_list(p);
system("cls");
printf("添加完成\n");
}
//打印所有信息
void Output_list(QST head)
{
QST p=head;
system("cls");
printf("开始输出\n");
if(Pd_list(p))
{
return;
}
int index=1;
while(p->next!=NULL)
{
p=p->next;
printf("第%d个学生信息:\n",index++);
printf("学号:%d\n",p->data.xh);
printf("姓名:%s\n",p->data.name);
printf("年龄:%d\n",p->data.age);
printf("性别:%s\n",p->data.sex);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
}
printf("输出完毕!\n");
}
//查询学生信息
void Seek_list(QST head)
{
QST p = head->next;
QST q = head;
while (true)
{
printf("开始查找\n");
printf("请选择查询方式:[1]按学号[2]按姓名[0]退出");
int num;
scanf("%d", &num);
switch (num)
{
case 1:
printf("请输入学生学号:\n");
int stuNum;
scanf("%d", &stuNum);
while (p != NULL)
{
if (p->data.xh == stuNum)
{
system("cls");
printf("学生姓名:%s,学生学号:%d\n", p->data.name, p->data.xh);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
return;
}
p = p->next;
}
if (p)
{
printf("没有查找到数据\n");
return;
}
case 2:
printf("请输入名字:\n");
getchar();
char name[20];
gets(name);
while (q != NULL)
{
if (strcmp(q->data.name, name) == 0)
{
printf("学生姓名:%s,学生学号:%d\n", q->data.name, q->data.xh);
return;
}
q = q->next;
}
if (q == NULL)
{
printf("没有查找到数据\n");
return;
}
case 0:
printf("退出\n");
return;
break;
default:
printf("用户输入有误请重新输入\n");
break;
}
}
}
//删除学生信息
void Delete_list(QST head)
{
QST p=head;
if(Pd_list(head))
{
return;
}
printf("开始删除\n");
printf("你想要全部删除[0] 还是单个删除[1]\n");
int num;
scanf("%d",&num);
if(num==0)
{
printf("正在全部删除中......\n");
Empty_list(head);
printf("全部删除成功\n");
}
else if(num==1)
{
printf("请输入你要删除学生的名字:");
char name[10];
getchar();
gets(name);
//被删除结点的前驱结点
QST qjd=p;
//当前要删除的结点
p=p->next;
while(strcmp(p->data.name,name))
{
if(p->next==NULL)
{
printf("没有找到这个人\n");
return;
}
qjd=p;
p=p->next;
}
qjd->next=p->next;
p->next=NULL;
free(p);
printf("删除成功\n");
return;
}
else
{
printf("用户输入错误\n");
}
}
//删除所有结点
void Empty_list(QST head)
{
QST p=head;
QST q=p->next;
while(q!=NULL)
{
p=q;
q=q->next;
p->next=NULL;
free(p);
}
return;
}
//修改学生信息
void Ament_list(QST head)
{
QST p=head;
if(Pd_list(head))
{
printf("修改失败\n");
return;
}
printf("开始修改\n");
printf("你要修改谁的信息(名字):");
char name[10];
getchar();
gets(name);
// 循环找到要修改的学生
while (p->next != NULL) {
p = p->next;
// 如果找到要修改的学生
if (strcmp(p->data.name, name) == 0) {
// 打印修改前的信息
printf("修改前的信息:\n");
printf("学号:%d, 姓名:%s, 年龄:%hd, 性别:%s\n", p->data.xh, p->data.name, p->data.age, p->data.sex);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
// 调用 Fuzhi 函数修改信息,包括新的科目成绩
Fuzhi(p);
// 打印修改后的信息
printf("修改后的信息:\n");
printf("学号:%d, 姓名:%s, 年龄:%hd, 性别:%s\n", p->data.xh, p->data.name, p->data.age, p->data.sex);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
return; // 结束函数,避免继续循环查找
}
}
// 如果循环结束仍未找到要修改的学生
printf("查无此人\n");
}
//赋值函数
void Fuzhi(QST p)
{
printf("学号:");
scanf("%d",&p->data.xh);
getchar();
printf("姓名:");
gets(p->data.name);
printf("年龄:");
scanf("%d",&p->data.age);
getchar();
printf("性别:");
gets(p->data.sex);
printf("语文成绩:");
scanf("%f", &p->data.chinese);
printf("数学成绩:");
scanf("%f", &p->data.math);
printf("英语成绩:");
scanf("%f", &p->data.english);
}
//插入函数
void Insert_list(QST head)
{
QST p=head;
if(Pd_list(head))
{
printf("请先添加,再插入\n");
return;
}
char name[10];
getchar();
printf("你要在谁的前面插入(名字):\n");
gets(name);
//找到插入位置
QST q=p;
p=p->next;
while(strcmp(p->data.name,name))
{
if(p->next==NULL)
{
printf("没有找到这个人\n");
return;
}
q=p;
p=p->next;
}
Linked_list(q);
Ass_list(q);
//循环找到尾结点
while(q->next!=NULL)
{
q=q->next;
}
q->next=p;
printf("插入完成\n");
}
//学生成绩排序
void Sort_list(QST head)
{
QST p = head;
printf("开始排序\n");
if (Pd_list(head))
{
return;
}
// 计算链表长度
int len = 0;
QST jd = p;
while (jd->next != NULL)
{
jd = jd->next;
len++;
}
printf("请选择排序方式:[1]总分 [2]平均分 [3]语文成绩 [4]数学成绩 [5]英语成绩 [0]退出");
int sortOption;
scanf("%d", &sortOption);
QST a, b;
for (int i = 1; i < len; i++)
{
a = p->next;
b = a->next;
for (int j = 0; j < len - i; j++)
{
float scoreA, scoreB;
switch (sortOption)
{
case 1:
scoreA = a->data.chinese + a->data.math + a->data.english;
scoreB = b->data.chinese + b->data.math + b->data.english;
break;
case 2:
scoreA = (a->data.chinese + a->data.math + a->data.english)/3.0;
scoreB = (b->data.chinese + b->data.math + b->data.english)/3.0;
break;
case 3:
scoreA = a->data.chinese;
scoreB = b->data.chinese;
break;
case 4:
scoreA = a->data.math;
scoreB = b->data.math;
break;
case 5:
scoreA = a->data.english;
scoreB = b->data.english;
break;
case 0:
printf("退出\n");
return;
break;
default:
printf("用户输入有误请重新输入\n");
return;
}
if (scoreA > scoreB)
{
struct data temp = a->data;
a->data = b->data;
b->data = temp;
}
a = b;
b = b->next;
}
}
printf("排序完成\n");
}
// 输出不及格学生
void DisplayFailingStudents(QST head) {
QST p = head->next;
printf("不及格学生信息:\n");
while (p != NULL) {
if (p->data.chinese < 60 || p->data.math < 60 || p->data.english < 60) {
printf("学号:%d, 姓名:%s\n", p->data.xh, p->data.name);
printf("语文成绩: %.2f\n", p->data.chinese);
printf("数学成绩: %.2f\n", p->data.math);
printf("英语成绩: %.2f\n", p->data.english);
printf("\n");
}
p = p->next;
}
}
// 输出各科目最高分
void DisplayMaxScores(QST head) {
float maxChinese = 0, maxMath = 0, maxEnglish = 0;
QST p = head->next;
while (p != NULL) {
maxChinese = (p->data.chinese > maxChinese) ? p->data.chinese : maxChinese;
maxMath = (p->data.math > maxMath) ? p->data.math : maxMath;
maxEnglish = (p->data.english > maxEnglish) ? p->data.english : maxEnglish;
p = p->next;
}
printf("各科目最高分:\n");
printf("语文最高分: %.2f\n", maxChinese);
printf("数学最高分: %.2f\n", maxMath);
printf("英语最高分: %.2f\n", maxEnglish);
}