近些天有上机实验,所以要完成学生管理系统,以前只用python写过,这一次用链表和文件操作实现具有记忆功能的学生管理系统。
# include <stdio.h>
# include <stdlib.h>
# include <malloc.h>
# include <string.h>
typedef struct
{
char name[20];
long num; // 学号
float subjectScore[3]; // math Chinese English
float sum; //总分
}Stu;
struct Node
{
Stu data; // 数据域
struct Node* next;
};
// 储存结构:链表
// 1.创建链表
struct Node* createList()
{
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
headNode->next = NULL;
return headNode;
}
// 2.创建节点
struct Node* createNode(Stu data)
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 3.打印数据
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
printf("******************************************\n");
printf("name\tnum\tmath\tChinese\tEnglish\n");
while (pMove)
{
printf("%s\t%ld\t%5.1f\t%5.1f\t%5.1f\n", pMove->data.name, pMove->data.num, pMove->data.subjectScore[0],pMove->data.subjectScore[1], pMove->data.subjectScore[2]);
pMove = pMove->next;
}
printf("******************************************\n");
printf("\n");
}
// 4.1插入节点(头插法),插入哪一个链表,插入数据
void insertNodeByHead(struct Node* headNode, Stu data)
{
// 1.创建插入节点
struct Node* newNode = createNode(data);
newNode->next = headNode->next;
headNode->next = newNode;
}
// 4.2插入节点(尾插法)
void insertNodeByTail(struct Node* headNode, Stu data)
{
struct Node* newNode = createNode(data);
struct Node* t = createNode(data); // 转换量
for(t = headNode; t->next; t=t->next); //结束时t指向尾节点
newNode->next = NULL; //进行插入
t->next = newNode;
}
// 5.删除节点
void deleteNodeByAppoinNum(struct Node* headNode)
{
long num;
printf("请输入要删除的学号:\n");
scanf("%ld", &num);
struct Node* posNode = headNode->next;
struct Node* posNodeFront = headNode;
if (posNode == NULL)
{
printf("无法删除链表为空\n");
}
else
{
while (posNode->data.num != num)
{
posNodeFront = posNode;
posNode = posNodeFront->next;
if (posNode == NULL)
{
printf("未找到指定位置,无法删除\n");
return;
}
}
posNodeFront->next = posNode->next;
free(posNode);
printf("已删除!\n");
}
}
// 菜单功能
// 1.信息输入
void input (struct Node* headNode)
{
Stu info;
printf("请输入学生姓名:\n");
scanf("%s", info.name);
printf("请输入学号:\n");
scanf("%ld", &info.num);
printf("请输入数学成绩:\n");
scanf("%f", &info.subjectScore[0]);
printf("请输入语文成绩:\n");
scanf("%f", &info.subjectScore[1]);
printf("请输入英语成绩:\n");
scanf("%f", &info.subjectScore[2]);
insertNodeByHead(headNode, info);
printf("已经添加成功!\n");
printList(headNode);
}
// 2.总分统计
void count(struct Node* headNode)
{
struct Node* pMove = headNode->next;
while(pMove)
{
pMove->data.sum = pMove->data.subjectScore[0] + pMove->data.subjectScore[1] + pMove->data.subjectScore[2];
pMove = pMove->next;
}
pMove = headNode->next;
printf("已统计完成,如下:\n");
printf("******************************************\n");
printf("name\tsum\n");
while (pMove)
{
printf("%s\t%5.1f\n", pMove->data.name, pMove->data.sum);
pMove = pMove->next;
}
printf("******************************************\n");
printf("\n");
}
// 3.总分排序
void sort(struct Node* headNode)
{
Stu temp;
struct Node* pMove1 = headNode->next; // 冒泡
struct Node* pMove2 = headNode->next;
while (pMove1)
{
while(pMove2->next)
{
if (pMove2->data.sum < pMove2->next->data.sum)
{
temp = pMove2->data;
pMove2->data = pMove2->next->data;
pMove2->next->data = temp;
}
pMove2 = pMove2->next;
}
pMove1 = pMove1->next;
pMove2 = headNode->next;
}
pMove1 = headNode->next;
printf("已排序完成,如下:\n");
printf("******************************************\n");
printf("name\tsum\n");
while (pMove1)
{
printf("%s\t%5.1f\n", pMove1->data.name, pMove1->data.sum);
pMove1 = pMove1->next;
}
printf("******************************************\n");
printf("\n");
}
// 4.用学号查询学生
void query1(struct Node* headNode)
{
long num;
struct Node* pMove = headNode->next;
printf("请输入学号:");
scanf("%ld", &num);
while (pMove)
{
if (pMove->data.num == num)
{
printf("******************************************\n");
printf("name\tnum\tmath\tChinese\tEnglish\n");
printf("%s\t%ld\t%5.1f\t%5.1f\t%5.1f\n", pMove->data.name, pMove->data.num, pMove->data.subjectScore[0],pMove->data.subjectScore[1], pMove->data.subjectScore[2]);
printf("******************************************\n");
return;
}
pMove = pMove->next;
}
printf("没有此同学!\n");
}
// 5.查询分数段学生
void query2(struct Node* headNode)
{
char subjectName[20];
struct Node* pMove = headNode->next;
float begin, end;
printf("请输入要查询的课程名(math or Chinese or English):\n");
getchar();
gets(subjectName);
printf("请输入要查询的分数段(xx,xx):\n");
setbuf(stdin, NULL); // 清楚缓存,处理跳步
scanf("%f,%f", &begin, &end);
if (!strcmp("math", subjectName))
{
printf("******************************************\n");
printf("name\tmath\n");
while(pMove)
{
if (pMove->data.subjectScore[0]>=begin && pMove->data.subjectScore[0] <= end)
{
printf("%s\t%5.1f\n", pMove->data.name, pMove->data.subjectScore[0]);
}
pMove = pMove->next;
}
printf("******************************************\n");
}
else if (!strcmp("Chinese", subjectName))
{
printf("******************************************\n");
printf("name\tChinese\n");
while(pMove)
{
if (pMove->data.subjectScore[1]>=begin && pMove->data.subjectScore[1] <= end)
{
printf("%s\t%5.1f\n", pMove->data.name, pMove->data.subjectScore[1]);
}
pMove = pMove->next;
}
printf("******************************************\n");
}
else if (!strcmp("English", subjectName))
{
printf("******************************************\n");
printf("name\tEnglish\n");
while(pMove)
{
if (pMove->data.subjectScore[2]>=begin && pMove->data.subjectScore[2] <= end)
{
printf("%s\t%5.1f\n", pMove->data.name, pMove->data.subjectScore[2]);
}
pMove = pMove->next;
}
printf("******************************************\n");
}
else
{
printf("您的科目名称输入有误!\n");
}
}
// 8.保存链表信息到文件中
void saveStuData(struct Node* headNode)
{
struct Node* pMove = headNode->next;
FILE* fp;
if((fp=fopen("D:/student.txt","w"))==NULL)// 以可写的方式打开当前目录下的.txt
{
printf("不能打开此文件,请按任意键退出\n");
exit(1); //异常退出
}
while (pMove)
{
fprintf(fp, "%s %ld %5.1f %5.1f %5.1f\n",pMove->data.name, pMove->data.num, pMove->data.subjectScore[0], pMove->data.subjectScore[1], pMove->data.subjectScore[2]);
pMove = pMove->next;
}
printf("保存成功!\n");
fclose(fp);
}
//运行前把文件内容读取到链表中
void readStuData(struct Node* headNode)
{
Stu stu1;
FILE *fp;
fp = fopen("D:/student.txt","r");
if (fp == NULL)
{
printf("文件不存在!\n");
exit(0);
}
// 判断文件是否为空
getc(fp); // 让光标移动一个字符
if (feof(fp))
{
fclose(fp);
return;
}
else
{
rewind(fp); // 使光标初始化在开头
while (!feof(fp))
{
fscanf(fp, "%s %ld %f %f %f\n",stu1.name, &stu1.num, &stu1.subjectScore[0], &stu1.subjectScore[1], &stu1.subjectScore[2]);
// 尾插法插入数据
insertNodeByTail(headNode, stu1);
}
}
fclose(fp);
}
int main()
{
char choice = 'a';
struct Node* list = createList();
// Stu info = {"Tom",1001, {20,60,10}};
readStuData(list);
while (choice != '0')
{
printf("--------------成绩管理系统----------------\n");
printf("(1):信息输入(INPUT)\n");
printf("(2):总分统计(COUNT)\n");
printf("(3):总分排序(SORT)\n");
printf("(4):查询(QUERY)\n");
printf("(5):课程分数段查询(QUERY)\n");
printf("(6):删除学生信息(DELETE)\n");
printf("(7):显示全部(SHOWALL)\n");
printf("(8):保存当前学生信息(SAVEDATA)\n");
printf("------------------------------------------------\n");
printf("说明 :请先完成统计再进行排序\n");
printf("(0):退出(EXIT)\n");
printf("请选择<0~8>:\n");
scanf(" %c", &choice);
switch (choice)
{
case '1':
input(list);
break;
case '2':
count(list);
break;
case '3':
sort(list);
break;
case '4':
query1(list);
break;
case '5':
query2(list);
break;
case '6':
deleteNodeByAppoinNum(list);
case '7':
printList(list);
break;
case '8':
saveStuData(list);
break;
break;
default:
break;
};
}
return 0;
}
其中最让我难忘的是文件操作和循环输入scanf输入单个字符, 这两个废了不少时间,文件操作先不说,scanf循环时有跳步现象,然后加上setbuf(stdin,NULL)关闭缓存区后,再输入字符串,字符串是中文时会出现个别字体消失现象,看了网上的许多博客用fflush清楚缓存并没有好的解决,最后看了以为大神的博客,只需要不加setbuf,使前面的scanf括号中的“%c”百分号前面加一个空格即可,即scanf(" %c", choice),详细请看代码。
好了,本人实属入门级C语言的大学生,如有不对之处,欢迎留言批正。