#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 学生信息结构体
struct Student
{
// 学号
long stuid;
// 姓名
char stuname[20];
};
// 作业信息结构体
struct Homework
{
// 作业编号
long worksno;
// 作业内容
char workdata[100];
// 作业成绩指针
// struct list_node *p;
};
// 作业成绩单链表
struct list_node
{
//数据域,用于存储数据
// 学号
long stuid;
// 作业编号
long worksno;
// 作业成绩
float grade;
//指针,可以用来访问节点数据,也可以遍历,指向下一个节点
struct list_node *next;
};
// 作业成绩结构体
struct Grade
{
// 学号
long stuid;
// 作业编号
long worksno;
// 作业成绩
float grade;
};
// 新增学生信息
void addStuInfo(struct Student stu[], int count)
{
printf("请输入学号 姓名:\n");
scanf("%d", &stu[count].stuid);
scanf("%s", &stu[count].stuname);
}
// 修改学生信息
void updStuInfo(struct Student stu[], int count)
{
long stuid;
printf("请输入学号:\n");
scanf("%d", &stuid);
// 遍历数组 找到输入学号 并修改
for (int i = 0; i < count; i++)
{
if (stu[i].stuid == stuid)
{
printf("请输入更改姓名:\n");
scanf("%s", &stu[i].stuname);
return;
}
}
// 未找到 打印该信息
printf("无此学号记录!\n");
}
// 查询学生信息
void qryStuInfo(struct Student stu[], int count)
{
printf("学号\t姓名\n");
// 遍历数组 打印学号 姓名信息
for (int i = 0; i < count; i++)
{
printf("%d\t%s\n", stu[i].stuid, stu[i].stuname);
}
}
// 新增作业信息
void addWorkInfo(struct Homework work[], int count)
{
printf("请输入作业内容:\n");
work[count].worksno = count;
scanf("%s", &work[count].workdata);
}
// 修改作业信息
void updWorkInfo(struct Homework work[], int count)
{
long wordsno;
printf("请输入作业编号:\n");
scanf("%d", &wordsno);
// 遍历数组 找到输入对应作业编号 并修改
for (int i = 0; i < count; i++)
{
if (work[i].worksno == wordsno)
{
printf("请输入更改内容:\n");
scanf("%s", &work[i].workdata);
return;
}
}
// 未找到 打印该信息
printf("无此作业记录!\n");
}
// 查询作业信息
void qryWorkInfo(struct Homework work[], int count)
{
printf("作业编号\t作业内容\n");
// 遍历数组 打印作业编号 作业内容信息
for (int i = 0; i < count; i++)
{
printf("%d\t\t%s\n", work[i].worksno, work[i].workdata);
}
}
// 创建成绩信息
struct list_node *createGradeInfo(long stuid, long worksno, float grade)
{
//给每个节点分配结构体一样的空间大小
struct list_node *p = malloc(sizeof(struct list_node));
if (NULL == p)
{
printf("malloc error!\n");
return NULL;
}
//由于结构体在未初始化的时候一样是脏数据,所以要清
memset(p, 0, sizeof(struct list_node));
//初始化第一个节点 进行赋值
p->stuid = stuid;
p->worksno = worksno;
p->grade = grade;
//将节点的后继指针设置为NULL
p->next = NULL;
return p;
}
// 插入成绩信息
void insertGradeInfo(struct list_node *pH, struct list_node *new)
{
//获取当前的位置
struct list_node *p = pH;
//如果当前位置的下一个节点不为空
while (p->next)
{
//移动到下一个节点
p = p->next;
}
//如果跳出以上循环,所以已经到了NULL的这个位置
//此时直接把新插入的节点赋值给NULL这个位置
p->next = new;
}
// 录入 修改成绩
void updGrade(struct list_node *pH)
{
long stuid;
long worksno;
printf("请输入学号 作业编号:\n");
scanf("%d", &stuid);
scanf("%d", &worksno);
struct list_node *p = pH;
//如果当前位置的下一个节点不为空
while (p->next)
{
p = p->next;
if (p->stuid == stuid
&&p->worksno == worksno)
{
float grade;
printf("请输入成绩:\n");
scanf("%.2f", &grade);
p->grade = grade;
return;
}
}
printf("未找到该学号 作业号信息!\n");
}
// 查看所有成绩信息
void showAllGrade(struct list_node *pH)
{
//获取当前的位置
struct list_node *p = pH;
printf("学号\t作业编号\t作业成绩\n");
//如果当前位置的下一个节点不为空
while (p->next)
{
p = p->next;
printf("%d\t%d\t\t%.2f\n", p->stuid, p->worksno, p->grade);
}
}
// 根据作业编号查看所有成绩
void showAllGradeByWorksno(struct list_node *pH)
{
long worksno;
printf("请输入作业编号:\n");
scanf("%d", &worksno);
//获取当前的位置
struct list_node *p = pH;
printf("学号\t作业编号\t作业成绩\n");
//如果当前位置的下一个节点不为空
while (p->next)
{
p = p->next;
if (p->worksno == worksno)
{
printf("%d\t%d\t\t%.2f\n", p->stuid, p->worksno, p->grade);
}
}
}
// 根据作业编号查看没有成绩学生信息
void showAllGradeByWorksnoWithNoGrade(struct list_node *pH)
{
long worksno;
printf("请输入作业编号:\n");
scanf("%d", &worksno);
//获取当前的位置
struct list_node *p = pH;
printf("学号\t作业编号\t作业成绩\n");
//如果当前位置的下一个节点不为空
while (p->next)
{
p = p->next;
if (p->worksno == worksno && p->grade == 0)
{
printf("%d\t%d\t\t%.2f\n", p->stuid, p->worksno, p->grade);
}
}
}
// 查看作业平均分
void showAvgGrade(struct list_node *pH, struct Homework work[], int stucount)
{
// 该数组 存放对应作业总分
float sum = 0;
long worksno;
printf("请输入作业编号:\n");
scanf("%d", &worksno);
//获取当前的位置
struct list_node *p = pH;
//如果当前位置的下一个节点不为空
while (p->next)
{
p = p->next;
if (p->worksno == worksno)
{
sum += p->grade;
}
}
printf("作业编号\t平均分\n");
printf("%d\t\t%.2f\n", worksno, sum / stucount);
}
// 根据作业编号查看所有成绩(降序)
void showAllGradeByWorksnoDesc(struct list_node *pH, int stucount)
{
// 定义grade动态数组 存储每个学生 成绩
struct Grade* const grade = (struct Grade*)malloc(sizeof(struct Grade*)*stucount);
long worksno;
printf("请输入作业编号:\n");
scanf("%d", &worksno);
//获取当前的位置
struct list_node *p = pH;
printf("学号\t作业编号\t作业成绩\n");
// 将作业编号为worksno 的学生成绩信息存入grade数组
int n = 0;
while (p->next)
{
p = p->next;
if (p->worksno == worksno)
{
grade[n].stuid = p->stuid;
grade[n].worksno = worksno;
grade[n].grade = p->grade;
n++;
}
}
// 对grade数组进行排序(倒序)
int i, j;
struct Grade temp;
for (i = 0; i < stucount; ++i) {
for (j = stucount - 1; j > i; --j) {
if (grade[j].grade > grade[j - 1].grade) {
temp = grade[j];
grade[j] = grade[j - 1];
grade[j - 1] = temp;
}
}
}
// 遍历 打印信息
for (int i = 0; i < stucount; ++i) {
printf("%d\t%d\t\t%.2f\n", grade[i].stuid, grade[i].worksno, grade[i].grade);
}
}
// 单链表释放
void Free_list(struct list_node *pHead) //释放链表
{
struct list_node * p;
while (pHead != NULL)
{
p = pHead;
pHead = pHead->next;
free(p);
p = NULL;
}
}
int main()
{
// 学生数量统计
int stucount = 0;
// 作业数量统计(作业编号)
int workcount = 0;
// 作业成绩统计
int gradecount = 0;
// 定义学生信息结构体数组
struct Student stu[100];
// 定义作业信息结构体数组
struct Homework work[100];
// 创建单链表头结点
struct list_node *header = createGradeInfo(0, 0, 0);
int n = 0;
long stuid;
// 从文件读取学生信息
FILE *frStu = fopen("stuinfo.txt", "r");
if (frStu != NULL)
{
char StrLine[1024];
while (!feof(frStu))
{
fgets(StrLine, 1024, frStu); // 读取一行
// 去除读取行末尾\n换行符 保证显示正常
if (StrLine[strlen(StrLine) - 1]=='\n')
{
StrLine[strlen(StrLine) - 1] = '\0';
}
char* temp = strtok(StrLine, " ");// 按空格 分开 取学号
char* temp1 = strtok(NULL, " ");// 取姓名
// char* 转long 对学号赋值
stu[stucount].stuid = strtol(temp, NULL, 10);
// 对姓名赋值
strcpy(stu[stucount].stuname, temp1);
stucount++;
}
fclose(frStu);
}
// 从文件读取作业信息
FILE *frWork = fopen("work.txt", "r");
if (frWork != NULL)
{
char StrLine[1024];
while (!feof(frWork))
{
fgets(StrLine, 1024, frWork); // 读取一行
// 去除读取行末尾\n换行符 保证显示正常
if (StrLine[strlen(StrLine) - 1] == '\n')
{
StrLine[strlen(StrLine) - 1] = '\0';
}
// 文件 内容为空 跳过
char* temp = strtok(StrLine, " ");// 按空格 分开 作业编号
char* temp1 = strtok(NULL, " ");// 取作业内容
// char* 转long 对作业编号赋值
work[workcount].worksno = strtol(temp, NULL, 10);
// 对作业内容赋值
strcpy(work[workcount].workdata, temp1);
workcount++;
}
fclose(frWork);
}
// 从文件读取成绩信息
FILE *frGrade = fopen("grade.txt", "r");
if (frGrade != NULL)
{
char StrLine[1024];
while (!feof(frGrade))
{
fgets(StrLine, 1024, frGrade); // 读取一行
// 去除读取行末尾\n换行符 保证显示正常
if (StrLine[strlen(StrLine) - 1] == '\n')
{
StrLine[strlen(StrLine) - 1] = '\0';
}
// 文件 内容为空 跳过
char* temp = strtok(StrLine, " ");// 取学号
char* temp1 = strtok(NULL, " ");// 取作业编号
char* temp2 = strtok(NULL, " ");// 取成绩
insertGradeInfo(header, createGradeInfo(strtol(temp, NULL, 10), strtol(temp1, NULL, 10), strtof(temp2, NULL)));
gradecount++;
}
fclose(frGrade);
}
while (n != 3)
{
printf("请选择访问角色:\n");
printf("1.教师 2.学生 3.退出\n");
scanf("%d", &n);
if (n == 1)
{
// 教师模块
int n1 = 0;
while (n1 != 4)
{
printf("请选择操作内容:\n");
printf("1.学生信息管理 2.作业信息管理 3.作业成绩管理 4.返回\n");
scanf("%d", &n1);
if (n1 == 1)
{
int n2 = 0;
while (n2 != 4)
{
printf("请选择操作内容:\n");
printf("1.增加学生信息 2.修改学生信息 3.查询学生信息 4.返回\n");
scanf("%d", &n2);
if (n2 == 1)
{
addStuInfo(stu, stucount);
// 新增后 学生记录数加1
stucount++;
}
else if (n2 == 2)
{
updStuInfo(stu, stucount);
}
else if (n2 == 3)
{
qryStuInfo(stu, stucount);
}
}
}
else if (n1 == 2)
{
int n3 = 0;
while (n3 != 5)
{
printf("请选择操作内容:\n");
printf("1.增加作业信息 2.修改作业信息 3.查询作业信息 4.删除作业信息 5.返回\n");
scanf("%d", &n3);
if (n3 == 1)
{
addWorkInfo(work, workcount);
// 创建作业时 更新所有学生该作业成绩链表 默认成绩为0
for (int i = 0; i < stucount; i++)
{
insertGradeInfo(header, createGradeInfo(stu[i].stuid, work[workcount].worksno, 0));
}
// 新增后 作业记录数加1
workcount++;
}
else if (n3 == 2)
{
updWorkInfo(work, workcount);
}
else if (n3 == 3)
{
qryWorkInfo(work, workcount);
}
else if (n3 == 4)
{
long worksno;
printf("请输入要删除的作业编号:\n");
scanf("%d", &worksno);
int delRow = -1;
for (int i = 0; i < workcount; i++)
{
if (worksno == work[i].worksno)
{
// 找到后并记录当前数据的下标(索引)
delRow = i;
break;
}
}
// 根据索引的判断,如果你要删除的数的下标和所给定索引的初值相同,那么肯定就是没找到。
if (delRow == -1)
{
printf("没有找到该作业!\n");
}
else
{
// 如果找到了,建立一个循环并且从下标开始,数组中的元素后面一个覆盖前面一个,且数组长度 - 1
for (int i = delRow; i < workcount - 1; i++)
{
work[i] = work[i + 1];
}
// 删除成功后 作业记录数减1
workcount--;
// 删除成功后 清除作业成绩单链表该作业信息 并释放内存
struct list_node *p, *q, *s;
p = header;
q = header->next;
while (q) {
if (q->worksno == worksno)
{
p->next = q->next;
s = q;
q = q->next;
free(s);
}
else {
p = p->next;
q = q->next;
}
}
}
}
}
}
else if (n1 == 3)
{
int n4 = 0;
while (n4 != 8)
{
printf("请选择操作内容:\n");
printf("1.录入成绩 2.修改成绩 3.查看所有成绩 4.根据作业编号查看所有成绩 5.根据作业编号查看没有成绩学生信息 \n");
printf("6.查看作业平均分 7.根据作业编号查看所有成绩(降序) 8.返回\n");
scanf("%d", &n4);
if (n4 == 1)
{
updGrade(header);
}
else if (n4 == 2)
{
updGrade(header);
}
else if (n4 == 3)
{
showAllGrade(header);
}
else if (n4 == 4)
{
showAllGradeByWorksno(header);
}
else if (n4 == 5)
{
showAllGradeByWorksnoWithNoGrade(header);
}
else if (n4 == 6)
{
showAvgGrade(header, work, stucount);
}
else if (n4 == 7)
{
showAllGradeByWorksnoDesc(header, stucount);
}
}
}
}
}
else if (n == 2)
{
printf("请输入学号:\n");
scanf("%d", &stuid);
// 学生模块
int n5 = 0;
while (n5 != 4)
{
printf("请选择操作内容:\n");
printf("1.查看所有成绩信息 2.查看第N次作业信息 3.查看作业总分及平均分 4.返回\n");
scanf("%d", &n5);
if (n5 == 1)
{
//获取当前的位置
struct list_node *p = header;
printf("学号\t作业编号\t作业成绩\n");
//如果当前位置的下一个节点不为空
while (p->next)
{
p = p->next;
if (p->stuid == stuid)
{
printf("%d\t%d\t\t%.2f\n", p->stuid, p->worksno, p->grade);
}
}
}
else if (n5 == 2)
{
long count;
printf("请输入第几次:\n");
scanf("%d", &count);
int i = 0;
//获取当前的位置
struct list_node *p = header;
printf("学号\t作业编号\t作业成绩\n");
//如果当前位置的下一个节点不为空
while (p->next)
{
p = p->next;
if (p->stuid == stuid)
{
i++;
if (i == count)
{
printf("%d\t%d\t\t%.2f\n", p->stuid, p->worksno, p->grade);
break;
}
}
}
}
else if (n5 == 3)
{
float sum = 0;
struct list_node *p = header;
//如果当前位置的下一个节点不为空
while (p->next)
{
p = p->next;
if (p->stuid == stuid)
{
sum += p->grade;
}
}
printf("总分\t\t平均分\n");
printf("%.2f\t%.2f\n", sum, sum / workcount);
}
}
}
}
// 保存学生信息
FILE *fwStu = fopen("stuinfo.txt", "w");
if (fwStu != NULL)
{
char buffer[20];
for (int i = 0; i < stucount; i++)
{
fputs(ltoa(stu[i].stuid, buffer, 10), fwStu);
fputs(" ", fwStu);
fputs(stu[i].stuname, fwStu);
// 最后一行记录 末尾不能存\n 不然会多空行
if (i != stucount - 1)
{
fputs("\n", fwStu);
}
}
fclose(fwStu);
}
// 保存作业信息
FILE *fwWork = fopen("work.txt", "w");
if (fwWork != NULL)
{
char buffer[20];
for (int i = 0; i < workcount; i++)
{
fputs(ltoa(work[i].worksno, buffer, 10), fwWork);
fputs(" ", fwWork);
fputs(work[i].workdata, fwWork);
// 最后一行记录 末尾不能存\n 不然会多空行
if (i != workcount - 1)
{
fputs("\n", fwWork);
}
}
fclose(fwWork);
}
// 保存成绩信息
FILE *fwGrade = fopen("grade.txt", "w");
if (fwGrade != NULL)
{
char buffer[20];
struct list_node *p = header;
while (p->next)
{
p = p->next;
fputs(ltoa(p->stuid, buffer, 10), fwGrade);
fputs(" ", fwGrade);
fputs(ltoa(p->worksno, buffer, 10), fwGrade);
fputs(" ", fwGrade);
sprintf(buffer, "%.2f ", p->grade);
fputs(buffer, fwGrade);
// 最后一行记录 末尾不能存\n 不然会多空行
if (p->next != NULL)
{
fputs("\n", fwGrade);
}
}
fclose(fwGrade);
}
// 释放单链表
Free_list(header);
system("pause");
return 0;
}
学习、交流 qq8660673