1.解决学生管理系统,首先先准备好封面,帮助我们执行指令。
void menu()//学生管理系统封面
{
printf("------------------------------------------\n");
printf("--\t\t1.浏览信息\t\t--\n");
printf("--\t\t2.添加信息\t\t--\n");
printf("--\t\t3.删除信息\t\t--\n");
printf("--\t\t4.查找信息\t\t--\n");
printf("--\t\t5.修改信息\t\t--\n");
printf("--\t\t6.退出系统\t\t--\n");
printf("------------------------------------------\n");
printf("请输入(1-6):\n");
}
运行结果
------------------------------------------
-- 1.浏览信息 --
-- 2.添加信息 --
-- 3.删除信息 --
-- 4.查找信息 --
-- 5.修改信息 --
-- 6.退出系统 --
------------------------------------------
请输入(1-6):
输入指令只需在重复循环中使用switch语句即可。
2.创建两个结构体,一个来存放学生的信息,比如学号、姓名、成绩等等,一个来支撑链表的实现。
struct studentdata//设置学生信息结构体
{
char id[30], name[30];
int chinese, math, english, sum, aver;
};
typedef struct list//创建链表
{
struct studentdata data;
struct list* next;
}list;
3.首先完成指令1,浏览学生信息,只需将表头输入进函数,用一个循环,当下一节指向空时,停止循环,期间不断打印经过的学生信息。
void printlist(list* mylist)//打印链表的数据
{
list* p = mylist->next;
printf("学号\t姓名\t语文\t数学\t英语\t总分\t平均分\n");
while (p != NULL)//当不为空时,打印当前节点对应数据
{
printf("%s\t%s\t%d\t%d\t%d\t%d\t%d\n",
p->data.id,
p->data.name,
p->data.chinese,
p->data.math,
p->data.english,
p->data.sum,
p->data.aver);
p = p->next;//指向下一个节点
}
}
4。完成指令2,添加学生信息,这个操作需要为添加的信息创建一个节点。
list* creatnode(struct studentdata data)//新建一个节点,用于后续的插入操作
{
list* newlist = (list*)malloc(sizeof(list));
newlist->data = data;//当前为传入的数据
newlist->next = NULL;//下一节定为空
return newlist;
}
通过插入,新的节点变成了表头
代码实现如下:
void insert(list* mylist, struct studentdata data)//插入数据
{
list* newlist = creatnode(data);//为插入的数据新建一个节点
newlist->next = mylist->next;
mylist->next = newlist;
}
插入后,便成功添加了学生信息。
5.完成指令3,删除学生信息,我们设想一下你要从链表中删除指定的学生信息,那我们一定要先找到这个学生的信息,我们这里用学生的学号来查找需要删除的学生。我们可以用一个while循环来找,当节点查找到学生学号或者指向链表尾部并且没有查找到学生学号会停止循环,这时我们判断这个链表所指向是否为空,如果是空,那说明它是因为指向了NULL才停止循环,反正,这个链表正指向我们要删除的学生信息。
在删除操作中,我们找到要删除的节点,可以找到删除节点的前节点,直接将它的前节点指向它的后节点便完成了删除操作。
将删除的节点的内存释放。
注意:还需要判定是否找到!
理论成立,代码实现:
void deletedata(list* mylist, char* id)//信息删除函数,根据传入的学生学号,删除该学生的信息
{
list* temp = mylist->next;
list* pre = mylist;
while (temp != NULL && strcmp(temp->data.id, id) != 0)
{
pre = temp;//指向要删除节点的前节点
temp = temp->next;//继续前进
}
if (temp)//此时temp节点所执行的信息就为需要删除学生的信息
{
pre->next = temp->next;//断开temp前面和后面的节点,让它前面的节点直接指向后面的节点。
free(temp);//释放被删除的学生数据
}
else//此时的temp指向链表的尾部,但是还没有找到学生学号,说明这个学号在记录里不存在
{
printf("没有找到该学生的信息\n");
}
}
6.完成指令4、5、6,查找学生信息,直接使用删除操作的部分while循环代码即可。
void finddata(list* mylist, char* id)//信息查找,通过学生学号查找
{
list* temp = mylist->next;
while (temp != NULL && strcmp(temp->data.id, id) != 0)//当节点查找到学生学号或者指向链表尾部并且没有查找到学生学号会停止循环
{
temp = temp->next;
}
if (temp)//找到了,打印当前信息
{
printf("学号\t姓名\t语文\t数学\t英语\t总分\t平均分\n");
printf("%s\t%s\t%d\t%d\t%d\t%d\t%d\n",
temp->data.id,
temp->data.name,
temp->data.chinese,
temp->data.math,
temp->data.english,
temp->data.sum,
temp->data.aver);
}
else//找不到
{
printf("没有该学生信息!\n");
}
}
修改学生信息也是需要先找到指向你想修改的学生信息对应的节点,再创建一个结构体变量,将新的信息输入,将新的信息覆盖原来的信息。
void changedata(list* mylist, char* id)
{
list* temp = mylist->next;
while (temp != NULL && strcmp(temp->data.id, id) != 0)
{
temp = temp->next;
}
if (temp)
{
struct studentdata newdata;
printf("请输入修改后的学生信息:\n学号\t姓名\t语文\t数学\t英语\n");
scanf("%s%s%d%d%d", newdata.id, newdata.name, &newdata.chinese, &newdata.math, &newdata.english);
newdata.sum = newdata.chinese + newdata.math + newdata.english;
newdata.aver = newdata.sum / 3;
temp->data = newdata;//信息修改
}
else
{
printf("没有该学生信息!\n");
}
}
指令6直接return 0。
7.学生总是要将成绩做比较来排名的,所以我们要将总分高的学生排在前面,在浏览时可以清楚观察排名,我们可以使用冒泡排序将链表排好序。
void sort(list* mylist)//这里使用冒泡排序对链表进行排序
{
for (list* turn = mylist->next; turn->next != NULL; turn = turn->next)//相当于将所有相邻的元素比对n次,n为链表的长度
{
for (list* move = mylist->next; move->next != NULL; move = move->next)//每次从表头出发,遍历到尾部
{
if (move->data.sum < move->next->data.sum)//当前面的学生总分大于后面的,做交换
{
studentdata temp = move->data;
move->data = move->next->data;
move->next->data = temp;
}
}
}
}
8.最后代码基本完成,但是当我们重新运行代码,之前输入的学生信息又要重新输入,这样是不是很麻烦,这时我们可以进行文件操作,将数据储存在文件里面。
先是添加读取文件的函数,将文件内的信息传入到我们的链表中。
void rfile(list* mylist, const char* filename)//读文件,将文件读取加载出来,当我们重新启动代码运行时可以得到原先写入的信息
{
FILE* fp = fopen(filename, "r");//打开
if (fp == NULL)
{
fp = fopen(filename, "w+");
fclose(fp);//当文件没有东西,就关闭
}
struct studentdata temp;
while (fscanf(fp, "%s\t%s\t%d\t%d\t%d\t%d\t%d\n",
temp.id,
temp.name,
&temp.chinese,
&temp.math,
&temp.english,
&temp.sum,
&temp.aver) != EOF)
{
insert(mylist, temp);//将文件内的学生信息插入链表里面
}
}
再添加写入文件的函数,将我们每次保存的信息添加入文件保存下来。
void sfile(list* mylist, const char* filename)//写文件,将信息保持到文件里面
{
list* pmove = mylist->next;
FILE* fp = fopen(filename, "w");//打开
while (pmove != NULL)
{
fprintf(fp, "%s\t%s\t%d\t%d\t%d\t%d\t%d\n",//将学生信息写入文件
pmove->data.id,
pmove->data.name,
pmove->data.chinese,
pmove->data.math,
pmove->data.english,
pmove->data.sum,
pmove->data.aver
);
pmove = pmove->next;
}
fclose(fp);//打开后要关闭
}
将这rfile函数放在运行开始的地方,直接读入文件,在添加信息、修改信息和删除信息函数中添加sfile函数,更新我们进行的修改,将其写入文件,具体操作看最下面完整代码。
最后让我们看看效果。
这时找到我们的文件夹中的对应名称的.txt文件。
点开后发现我们已经存下我们输入的信息。
在下一次重新运行代码时,通过读入文件我们便可以找到存入的学生信息,不用重新输入。
最后最后,完整代码奉上:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct studentdata//设置学生信息结构体
{
char id[30], name[30];
int chinese, math, english, sum, aver;
};
typedef struct list//创建链表
{
struct studentdata data;
struct list* next;
}list;
list* creatlist()//创建表头
{
list* mylist = (list*)malloc(sizeof(list));
mylist->next = NULL;//初始为空
return mylist;
}
list* creatnode(struct studentdata data)//新建一个节点,用于后续的插入操作
{
list* newlist = (list*)malloc(sizeof(list));
newlist->data = data;//当前为传入的数据
newlist->next = NULL;//下一节定为空
return newlist;
}
void insert(list* mylist, struct studentdata data)//插入数据
{
list* newlist = creatnode(data);//为插入的数据新建一个节点
newlist->next = mylist->next;
mylist->next = newlist;
}
void rfile(list* mylist, const char* filename)//读文件,将文件读取加载出来,当我们重新启动代码运行时可以得到原先写入的信息
{
FILE* fp = fopen(filename, "r");//打开
if (fp == NULL)
{
fp = fopen(filename, "w+");
fclose(fp);//当文件没有东西,就关闭
}
struct studentdata temp;
while (fscanf(fp, "%s\t%s\t%d\t%d\t%d\t%d\t%d\n",
temp.id,
temp.name,
&temp.chinese,
&temp.math,
&temp.english,
&temp.sum,
&temp.aver) != EOF)
{
insert(mylist, temp);//将文件内的学生信息插入链表里面
}
}
void sfile(list* mylist, const char* filename)//写文件,将信息保持到文件里面
{
list* pmove = mylist->next;
FILE* fp = fopen(filename, "w");//打开
while (pmove != NULL)
{
fprintf(fp, "%s\t%s\t%d\t%d\t%d\t%d\t%d\n",//将学生信息写入文件
pmove->data.id,
pmove->data.name,
pmove->data.chinese,
pmove->data.math,
pmove->data.english,
pmove->data.sum,
pmove->data.aver
);
pmove = pmove->next;
}
fclose(fp);//打开后要关闭
}
void printlist(list* mylist)//打印链表的数据
{
list* p = mylist->next;
printf("学号\t姓名\t语文\t数学\t英语\t总分\t平均分\n");
while (p != NULL)//当不为空时,打印当前节点对应数据
{
printf("%s\t%s\t%d\t%d\t%d\t%d\t%d\n",
p->data.id,
p->data.name,
p->data.chinese,
p->data.math,
p->data.english,
p->data.sum,
p->data.aver);
p = p->next;//指向下一个节点
}
}
void deletedata(list* mylist, char* id)//信息删除函数,根据传入的学生学号,删除该学生的信息
{
list* temp = mylist->next;
list* pre = mylist;
while (temp != NULL && strcmp(temp->data.id, id) != 0)
{
pre = temp;//指向要删除节点的前节点
temp = temp->next;//继续前进
}
if (temp)//此时temp节点所执行的信息就为需要删除学生的信息
{
pre->next = temp->next;//断开temp前面和后面的节点,让它前面的节点直接指向后面的节点。
free(temp);//释放被删除的学生数据
sfile(mylist, "学生成绩表.txt");
}
else//此时的temp指向链表的尾部,但是还没有找到学生学号,说明这个学号在记录里不存在
{
printf("没有找到该学生的信息\n");
}
}
void finddata(list* mylist, char* id)//信息查找,通过学生学号查找
{
list* temp = mylist->next;
while (temp != NULL && strcmp(temp->data.id, id) != 0)//当节点查找到学生学号或者指向链表尾部并且没有查找到学生学号会停止循环
{
temp = temp->next;
}
if (temp)//找到了,打印当前信息
{
printf("学号\t姓名\t语文\t数学\t英语\t总分\t平均分\n");
printf("%s\t%s\t%d\t%d\t%d\t%d\t%d\n",
temp->data.id,
temp->data.name,
temp->data.chinese,
temp->data.math,
temp->data.english,
temp->data.sum,
temp->data.aver);
}
else//找不到
{
printf("没有该学生信息!\n");
}
}
void changedata(list* mylist, char* id)
{
list* temp = mylist->next;
while (temp != NULL && strcmp(temp->data.id, id) != 0)
{
temp = temp->next;
}
if (temp)
{
struct studentdata newdata;
printf("请输入修改后的学生信息:\n学号\t姓名\t语文\t数学\t英语\n");
scanf("%s%s%d%d%d", newdata.id, newdata.name, &newdata.chinese, &newdata.math, &newdata.english);
newdata.sum = newdata.chinese + newdata.math + newdata.english;
newdata.aver = newdata.sum / 3;
temp->data = newdata;//信息修改
sfile(mylist, "学生成绩表.txt");
}
else
{
printf("没有该学生信息!\n");
}
}
void sort(list* mylist)//这里使用冒泡排序对链表进行排序
{
for (list* turn = mylist->next; turn->next != NULL; turn = turn->next)
{
for (list* move = mylist->next; move->next != NULL; move = move->next)
{
if (move->data.sum < move->next->data.sum)
{
studentdata temp = move->data;
move->data = move->next->data;
move->next->data = temp;
}
}
}
}
void menu()//学生管理系统封面
{
printf("------------------------------------------\n");
printf("--\t\t1.浏览信息\t\t--\n");
printf("--\t\t2.添加信息\t\t--\n");
printf("--\t\t3.删除信息\t\t--\n");
printf("--\t\t4.查找信息\t\t--\n");
printf("--\t\t5.修改信息\t\t--\n");
printf("--\t\t6.退出系统\t\t--\n");
printf("------------------------------------------\n");
printf("请输入(1-6):\n");
}
int main()
{
list* mylist = creatlist();
rfile(mylist, "学生成绩表.txt");
while (1)//系统的重复输入需要使用循环解决
{
menu();
int n = 0;
struct studentdata s;
scanf("%d", &n);
switch (n)//使用switch语句来判断输入指令,执行相关操作
{
case 1:
printlist(mylist);
break;
case 2:
printf("请输入你想添加的学生信息:\n学号\t姓名\t语文\t数学\t英语\n");
scanf("%s%s%d%d%d", s.id, s.name, &s.chinese, &s.math, &s.english);
s.sum = s.chinese + s.math + s.english;
s.aver = s.sum / 3;
insert(mylist, s);
sfile(mylist, "学生成绩表.txt");
break;
case 3:
char a[30];
printf("请输入你想删除学生的学号:\n");
scanf("%s", a);
deletedata(mylist, a);
break;
case 4:
char b[30];
printf("请输入你想查找学生的学号:\n");
scanf("%s", b);
finddata(mylist, b);
break;
case 5:
char c[30];
printf("请输入你想修改学生的学号:\n");
scanf("%s", c);
changedata(mylist, c);
break;
case 6:
return 0;
break;
default:
printf("输入错误\n");
break;
}
sort(mylist);//对每次的学生成绩排序
system("pause");
system("cls");
}
return 0;
}
此代码在Dev和vs皆可以运行。
本篇完~