本次我就用学到的相关链表知识总结回顾一下学生成绩管理系统的实现。
首先还是先创建一个项目,分别创建头文件和源文件,头文件用来声明函数,源文件用来定义函数以及实现学生成绩管理系统。
创建完成后如上图。
先创建一个结构体用来存放学生信息(学号,姓名,成绩),在这里学号我使用的是字符数组,整型可能不能满足学号长度的需要。
//学生信息
typedef struct student
{
char number[15];
char name[20];
float score;
}stu;
接着就是创建节点用来链接学生信息喽!节点如下:常规的放一个结构体(学生信息)以及下一个结点的地址。
//节点信息
typedef struct Node
{
stu student;
struct Node* next;
}node;
基本步骤就完成了。接下来是菜单,用来指引用户完成程序。菜单就用函数来实现(记得先在头文件里声明)。
void menu()
{
printf("\t*****************学生成绩管理系统***************\n");
printf("\t**************请选择功能列表********************\n");
printf("\t*******1.添加学生信息 2.打印学生信息*******\n");
printf("\t*******3.统计学生人数 4.查找学生信息*******\n");
printf("\t*******5.修改学生信息 6.删除学生信息*******\n");
printf("\t*******7.按成绩排序 8.退出系统***********\n");
}
菜单里的东西就是学生成绩系统将要完成的操作了。接下来我会详细说明每个步骤的实现。
同样用函数实现,为了方便实现链表的增删查改,需要使用一个头结点,头结点里不存放任何东西,只是方便链表操作,添加学生生信息即为给链表尾插一个新的节点,添加节点要注意的是要先向内存申请空间,因为申请的是节点空间,所以就要用结构体指针(节点地址)来接收,之后初始化新建节点,用scanf输入要添加的学生信息,之后就要进行尾插操作了,判断是否只有一个节点,若是,则直接将头结点的next指向新节点,若不是,找到尾结点,这就需要引出一个新节点用来找尾结点,循环遍历cur直至到最后一个节点,将最后一个节点指向新建节点即可。
void inputstudent(node* head)
{
node* fresh = (node*)malloc(sizeof(node));
fresh->next = NULL;
printf("请输入学生的学号、姓名、成绩:");
scanf("%s%s%f", fresh->student.number, fresh->student.name, &fresh->student.score);
if(head->next==NULL)
head->next = fresh;
else
{
node*cur = head;
while (cur->next != NULL)
{
cur = cur->next;
}
cur ->next= fresh;
}
}
打印学生信息也是需要一个可移动节点对链表进行遍历,依次打印即可。
void printstudent(node* head)
{
node* cur = head;
while (cur->next != NULL)
{
printf("学号:%s 姓名:%s 成绩:%.2f\n", cur->next->student.number, cur->next->student.name, cur->next->student.score);
cur = cur->next;
}
}
统计人数就是在遍历链表的过程中引入一个变量进行计数即可。
void countstudent(node* head)
{
int count = 0;
node* cur = head;
while (cur->next != NULL)
{
count++;
cur = cur->next;
}
printf("学生的总人数为:%d\n", count);
}
查找学生信息时是通过学生的学号找出学生的各项信息,由于要让用户输入要查找的学生的学号,故要定义一个字符数组,之后将节点里的学生信息里的学号依次与用户输入的信息进行比较,比对成功输入该项学生的各项信息即可,比较时,由于是字符串之间的比较,所以要用到字符串比较函数strcmp,不可直接用”==“.
void findstudent(node* head)
{
char stu[20];
printf("请输入要查找的学生的学号:");
scanf("%s", stu);
node* cur = head;
while (cur->next != NULL)
{
if (strcmp(cur->next->student.number,stu) == 0)
{
printf("学号:%s 姓名:%s 成绩:%.2f\n", cur->next->student.number, cur->next->student.name, cur->next->student.score);
return;
}
cur = cur->next;
}
printf("未找到该学生\n");
}
使学生信息更持久化
这个操作涉及到文件操作,先出 创建或打开文件(fopen),再向文件中写入数据(fwrite),遍历链表将每个节点保存到文件中。将该函数放置在添加学生信息的函数后即可。
void savestudent(node* head) { FILE* file = fopen("./stu.info", "w");//w即write可写 node* cur = head; while (cur->next != NULL) { if (fwrite(&cur->next->student, sizeof(stu), 1, file) != 1)//fwrite(要写入文件的数据的地址,数据的字节大小,传入数据的个数,传入的目标文件) { printf("写入失败\n"); return; } cur = cur->next; } fclose(file);//关闭文件 }
读取文件
打开之前存放过数据的文件,读取文件中的每个学生信息,将其连接到新链表中,用可移动的节点从头结点开始循环,先申请一个空间用来存放读取的第一个节点,之后将可移动节点的next链接到读取的数据存放的新申请空间的节点,可移动节点向后遍历,继续申请空间。直至文件中的数据全部被读取。注意最后要释放掉最后一次申请的空间,循环之前已经申请过一次空间,最后一次循环中申请的空间未被利用到。
void loadstudent(node* head) { FILE* file = fopen("./stu.info", "r");//r即read只读 if (!file) { printf("没有学生文件,跳过读取\n"); return; } node* fresh = (node*)malloc(sizeof(node)); node* cur = head; fresh->next = NULL; while (fread(&fresh->student, sizeof(stu), 1, file) == 1)//fread(读取出的数据存放的地址,读取出数据的字节大小,读取出数据的个数,读取数据的来源) { cur->next = fresh; cur = fresh; fresh = (node*)malloc(sizeof(node)); fresh->next = NULL; } free(fresh); fclose(file); printf("读取成功!\n"); }
此操作和查找学生信息有点相似,先让用户输入要修改的学生的学号,再循环遍历查找此学生修改即可,记得修改完成后将其存到文件中。
void modifystudent(node* head)
{
printf("请输入要修改的学生的学号:");
char stu[15];
scanf("%s", stu);
node* cur = head->next;
while (cur != NULL)
{
if (strcmp(cur->student.number, stu) == 0)
{
printf("请输入学生姓名,成绩:");
scanf("%s%f", cur->student.name, &cur->student.score);
savestudent(head);//持久化学生信息
printf("修改成功\n");
return;
}
cur = cur->next;
}
printf("未找到该学生\n");
}
先找到要删除的学生,注意要使用的是删除学生的前一个节点,将前一个节点与删除学生的下一个节点链接起来,删除学生的节点就不在链表中了,释放掉删除学生的空间即可。注意:不可直接将该节点删除,否则删除学生后面的节点就无法找到。
void deletestudent(node* head)
{
printf("请输入要删除的学生的学号:");
char stu[15];
scanf("%s", stu);
node* cur = head;
while (cur->next!=NULL)
{
if (strcmp(stu, cur->next->student.number) == 0)
{
node* tmp = cur->next;//记录删除的学生节点
cur->next = cur->next->next;
free(tmp);
tmp = NULL;
savestudent(head);
printf("删除成功\n");
return;
}
cur = cur->next;
}
printf("未找到该学生\n");
}
用冒泡排序对链表中的节点的数据进行排序(链表中结点的数据即为学生信息,直接交换学生信息即可,不用交换节点)。
结点的冒泡排序:
void sortstudent(node* head)
{
node* save = NULL;
node* cur = NULL;
for (node* turn = head->next; turn->next != NULL;turn=turn->next)
{
for ( cur = head->next; cur->next != save; cur = cur->next)
{
if (cur->next->student.score < cur->student.score)
{
stu temp = cur->student;
cur->student = cur->next->student;
cur->next->student = temp;
}
}
save = cur;//简化比较次数,最后面已经排序过的数据就不用再进行比较
}
printstudent(head);
}
StudentSystem.h:
#include
#include
#include
#include
//学生信息
typedef struct student
{
char number[15];
char name[20];
float score;
}stu;
//节点信息
typedef struct Node
{
stu student;
struct Node* next;
}node;
void menu();
//输入学生信息
void inputstudent(node* head);
//打印学生信息
void printstudent(node* head);
//统计学生人数
void countstudent(node* head);
//查找学生信息
void findstudent(node* head);
//使学生信息持久化 写入文件
void savestudent(node* head);
//读取文件
void loadstudent(node* head);
//修改学生信息
void modifystudent(node* head);
//删除学生信息
void deletestudent(node* head);
//按照学生成绩排序
void sortstudent(node* head);
StudentStystem.c:
#include"StudentStystem.h"
void menu()
{
printf("\t*****************学生成绩管理系统***************\n");
printf("\t**************请选择功能列表********************\n");
printf("\t*******1.添加学生信息 2.打印学生信息*******\n");
printf("\t*******3.统计学生人数 4.查找学生信息*******\n");
printf("\t*******5.修改学生信息 6.删除学生信息*******\n");
printf("\t*******7.按成绩排序 8.退出系统***********\n");
}
void inputstudent(node* head)
{
node* fresh = (node*)malloc(sizeof(node));
fresh->next = NULL;
printf("请输入学生的学号、姓名、成绩:");
scanf("%s%s%f", fresh->student.number, fresh->student.name, &fresh->student.score);
if(head->next==NULL)
head->next = fresh;
else
{
node*cur = head;
while (cur->next != NULL)
{
cur = cur->next;
}
cur ->next= fresh;
}
savestudent(head);
}
void printstudent(node* head)
{
node* cur = head;
while (cur->next != NULL)
{
printf("学号:%s 姓名:%s 成绩:%.2f\n", cur->next->student.number, cur->next->student.name, cur->next->student.score);
cur = cur->next;
}
}
void countstudent(node* head)
{
int count = 0;
node* cur = head;
while (cur->next != NULL)
{
count++;
cur = cur->next;
}
printf("学生的总人数为:%d\n", count);
}
void findstudent(node* head)
{
char stu[20];
printf("请输入要查找的学生的学号:");
scanf("%s", stu);
node* cur = head;
while (cur->next != NULL)
{
if (strcmp(cur->next->student.number,stu) == 0)
{
printf("学号:%s 姓名:%s 成绩:%.2f\n", cur->next->student.number, cur->next->student.name, cur->next->student.score);
return;
}
cur = cur->next;
}
printf("未找到该学生\n");
}
void savestudent(node* head)
{
FILE* file = fopen("./stu.info", "w");//w即write可写
node* cur = head;
while (cur->next != NULL)
{
if (fwrite(&cur->next->student, sizeof(stu), 1, file) != 1)//fwrite(要写入文件的数据的地址,数据的字节大小,传入数据的个数,传入的目标文件)
{
printf("写入失败\n");
return;
}
cur = cur->next;
}
fclose(file);//关闭文件
}
void loadstudent(node* head)
{
FILE* file = fopen("./stu.info", "r");//r即read只读
if (!file)
{
printf("没有学生文件,跳过读取\n");
return;
}
node* fresh = (node*)malloc(sizeof(node));
node* cur = head;
fresh->next = NULL;
while (fread(&fresh->student, sizeof(stu), 1, file) == 1)//fread(读取出的数据存放的地址,读取出数据的字节大小,读取出数据的个数,读取数据的来源)
{
cur->next = fresh;
cur = fresh;
fresh = (node*)malloc(sizeof(node));
fresh->next = NULL;
}
free(fresh);
fclose(file);
printf("读取成功!\n");
}
void modifystudent(node* head)
{
printf("请输入要修改的学生的学号:");
char stu[15];
scanf("%s", stu);
node* cur = head->next;
while (cur != NULL)
{
if (strcmp(cur->student.number, stu) == 0)
{
printf("请输入学生姓名,成绩:");
scanf("%s%f", cur->student.name, &cur->student.score);
savestudent(head);//持久化学生信息
printf("修改成功\n");
return;
}
cur = cur->next;
}
printf("未找到该学生\n");
}
void deletestudent(node* head)
{
printf("请输入要删除的学生的学号:");
char stu[15];
scanf("%s", stu);
node* cur = head;
while (cur->next!=NULL)
{
if (strcmp(stu, cur->next->student.number) == 0)
{
node* tmp = cur->next;
cur->next = cur->next->next;
free(tmp);
tmp = NULL;
savestudent(head);
printf("删除成功\n");
return;
}
cur = cur->next;
}
printf("未找到该学生\n");
}
void sortstudent(node* head)
{
node* save = NULL;
node* cur = NULL;
for (node* turn = head->next; turn->next != NULL;turn=turn->next)
{
for ( cur = head->next; cur->next != save; cur = cur->next)
{
if (cur->next->student.score < cur->student.score)
{
stu temp = cur->student;
cur->student = cur->next->student;
cur->next->student = temp;
}
}
save = cur;
}
printstudent(head);
}
test.c :
#include"StudentStystem.h"
int main()
{
//创建头结点
node* head = (node*)malloc(sizeof(node));
head->next = NULL;
loadstudent(head);
menu();
while (1)
{
char c = _getch();
switch (c)
{
case '1':
inputstudent(head);
break;
case '2':
printstudent(head);
break;
case '3':
countstudent(head);
break;
case '4':
findstudent(head);
break;
case '5':
modifystudent(head);
break;
case '6':
deletestudent(head);
break;
case '7':
sortstudent(head);
break;
case '8':
system("cls");
printf("欢迎下次使用\n");
exit(0);
break;
default:
printf("请重新输入:");
break;
}
}
return 0;
}
学生成绩管理系统到这里就完成啦,该系统与单链表的增删查改关系关系密切。大家想要多了解的话点击以下链接即可。
有关单链表更多接口函数的详细说明:
C语言实现单链表的各个接口函数