这个《学生成绩管理系统》是以前大一的时候的课设,今天整理文件的时候发现了,就直接把代码贴到博客上吧。挺基础的一个东西,就是涉及到C语言实现的链表,以及文件操作,结构体的序列化存储与读取等。
DataType.h
/*
编译环境:VS2017\Windows10
作者:smallerXuan
指导:
*/
#ifndef ___DDATA_TYPE__
#define ___DDATA_TYPE__
typedef struct grades //成绩
{
char id[20]; //学号
char subject[20]; //科目
float grade; //成绩
}Grade;
typedef struct GradeDataNode //成绩节点
{
Grade grades;
struct GradeDataNode *Pnext;
}GradeData;
typedef struct studentInformation //学生信息
{
char Class[30]; //班级
char name[30]; //姓名
char id[20]; //学号
}StudentInformation;
typedef struct StudentNode //学生节点
{
StudentInformation studentinfor;
struct StudentNode *Next;
}Student;
extern GradeData *pHeader_g,*pTail_g; //成绩链表头、尾
extern Student *pHeader_s,*pTail_s; //学生链表头、尾
extern char textGradeDataFile[20]; //成绩数据文件名称
extern char textStudentDataFile[20]; //学生数据文件名称
extern int isModified; //记录修改是否成功
#endif
StudentInfor.h
/*
编译环境:VS2017\Windows10
作者:smallerXuan
指导:
*/
#ifndef ___STUDENT_INFOR_H
#define ___STUDENT_INFOR_H
#include "DataType.h"
//对成绩数据及成绩节点的基本操作函数(共10个)
void inputGradeData(Grade *pGrade); // 输入成绩
void inputGradeDataNode(GradeData *pGradeNode); // 输入成绩节点
void printGradeData(Grade *pGrade); // 输出成绩
void printGradeDataNode(GradeData *pGradeNode); // 输出成绩节点
void printGradeDataAll(); // 输出所有成绩节点
void addAtGradeTail(GradeData *pNewNode_g); // 在成绩尾部添加节点
void deleteGradeNode(GradeData *pDeleted); // 删除成绩节点
void deleteGradeAll(); // 删除所有成绩节点
void editGradeNode(GradeData *pEdited); // 编辑成绩节点
GradeData *findAGradeData(); // 通过学号和科目 查询到准确的成绩节点
//对学生数据及学生节点的基本操作函数(共10个)
void inputStudentInformation(StudentInformation *pStudentInfor); // 输入学生信息
void inputStudentNode(Student *pStudentNode); // 输入学生节点
void printStudentInformation(StudentInformation *pStuInfor); // 输出学生信息
void printStudentNode(Student *pStudentNode); // 输出学生节点
void printStudentNodeAll(); // 输出所有学生节点
void addAtStudentTail(Student *pNewNoStudentNode); // 在学生尾部添加节点
void deleteStudentNode(Student *pDeleate); // 删除学生节点
void deleteStudentAll(); // 删除所有学生节点
void editStudentNode(Student *pEdite); // 编辑学生节点
Student *findByStudentId(); // 通过学生ID查询学生节点
#endif
Menu.h
/*
编译环境:VS2017\Windows10
作者:smallerXuan
指导:
*/
#ifndef ___MENU_H_
#define ___MENU_H_
#include
#include //提供 malloc() 和 free() 原型和定义
#include "DataType.h"
#include "StudentInfor.h"
//对界面的基本操作及响应函数(共6组,36个)
// 主菜单
void drawMainMenu(); //绘制主菜单
void doMainMenu(); //主菜单响应
void onMenuitemExit(); //在菜单退出
// 文件管理
void drawFileManagementMenu(); //绘制 文件管理 子菜单
void doFileManagementMenu(); //文件管理 子菜单 响应
void openGradeDataFromTextFile(); //从文本读入 成绩数据
void saveGradeDataInTextFile(); //保存成绩数据到文本
void saveStudentDataInTextFile(); //保存学生数据到文本
void openStudentDataFromTextFile(); //从文本读入 学生数据
// 数据维护
void drawDataMaintenanceMenu(); //绘制 数据维护 子菜单
void doDataMaintenanceMenu(); //数据维护 子菜单 响应
void drawDataMaintenanceMenu_s(); //绘制 数据维护 二级子菜单(成绩)
void doDataMaintenanceMenu_s(); //数据维护 二级子菜单(成绩)响应
void onMenueitemAddGrade(); //在菜单添加成绩记录
void onMenuitemEditeGrade(); //在菜单编辑成绩
void onMenuitemDeleteGrade(); //在菜单删除成绩节点
void drawDataMaintenanceMenu_g(); //绘制 数据维护 二级子菜单(学生)
void doDataMaintenanceMenu_g(); //数据维护 二级子菜单(学生)响应
void onMenueitemAddStudent(); //在菜单添加学生记录
void onMenuitemEditeStudent(); //在菜单编辑学生
void onMenuitemDeleteStudent(); //在菜单删除学生节点
// 数据查询
void drawDataQueryMenu(); //绘制 数据查询 子菜单
void doDataQueryMenu(); //数据查询 子菜单 响应
void drawStudentDataQueryMenu(); //绘制 数据查询 二级子菜单(学生)
void doStudentDataQueryMenu(); //数据查询 二级子菜单(学生) 响应
void onMenueitemBrowseStudent(); //在菜单浏览学生数据
void onMenueitemSearchStudent(); //在菜单查询学生数据
void drawGradeDataQueryMenu(); //绘制 数据查询 二级子菜单(成绩)
void doGradeDataQueryMenu(); //数据查询 二级子菜单(成绩) 响应
void onMenueitemBrowseGradeData(); //在菜单浏览成绩数据
void onMenueitemSearchGradeData(); //在菜单查询成绩数据
// 数据统计
void doDataCensuMenu(); //数据统计 子菜单 响应
void drawDataCensuMenu(); //绘制 数据统计 子菜单
void onMenueitemStatisticsStudent(); //在菜单统计学生成绩信息
//帮助文档
void drawHelpDocumentMenu(); //绘制 帮助文档 子菜单
void doHelpDocumentMenu(); //帮助文档 子菜单 响应
#endif
StudentInfor.c
/*
编译环境:VS2017\Windows10
作者:smallerXuan
指导:
*/
#include
#include
#include
#include
#include "DataType.h"
#include "StudentInfor.h"
//输入成绩
void inputGradeData(Grade *pGrade)
{
printf("学号:");
scanf("%s",&(pGrade->id));
printf("学科:");
scanf("%s",&(pGrade->subject));
printf("成绩:");
scanf("%f",&(pGrade->grade));
}
//输入成绩节点
void inputGradeDataNode(GradeData *pGradeNode)
{
inputGradeData(&(pGradeNode->grades)); //输入成绩节点的成绩
}
//输出成绩
void printGradeData(Grade *pGrade)
{
printf("\t%s\t%s\t%f\n",pGrade->id, pGrade->subject, pGrade->grade);
}
//输出成绩节点
void printGradeDataNode(GradeData *pGradeNode)
{
printGradeData(&(pGradeNode->grades)); //打印成绩节点的成绩
}
//输出所有成绩节点
void printGradeDataAll()
{
GradeData *p = pHeader_g; //指针指向成绩节的头
if(p == NULL)
{
puts("没有成绩记录");
}
else
{
printf("\t%s\t%s\t%s\n","学号","科目", "成绩" );
while(p!=NULL)
{
printGradeDataNode(p);
p=p->Pnext;
}
}
}
//在成绩尾部添加
void addAtGradeTail(GradeData *pNewNode_g)
{
if(pHeader_g == NULL) //无头时
{
pHeader_g = pTail_g = pNewNode_g;
}
else
{
pTail_g->Pnext = pNewNode_g;
pTail_g = pNewNode_g;
}
}
//删除成绩节点
void deleteGradeNode(GradeData *pDeleted)
{
GradeData *p,*q; //成绩节点型指针 p, q
p= q= pHeader_g; //p,q 赋值为成绩头指针
while(p!= pDeleted) //当要删除的节点不是头节点时 ,循环判断直到p为要删除的节点
{
q= p; //q 保存 P
p= p->Pnext; //p 指向该节点的 Pnext
}
if(p== pHeader_g) //如果p为头节点 ,此时头为p的后一个节点,即头部后移
{
pHeader_g= p->Pnext; //头指针指向该节点的Pnext
}
else if(p== pTail_g) //如果 p为 尾节点
{
q->Pnext= NULL; //q 的Pnext置空
pTail_g= q; //尾节点改为q ,此时尾为p的前一个节点,即尾部前移
}
else //普通节点时
{
q->Pnext= p->Pnext; //将该节点的前一个节点的Pnext设置为该节点的Pnext
}
free(p); //释放p
if(pHeader_g == NULL) //如果头部为空则尾部也置空
{
pTail_g= NULL;
}
}
//删除所有成绩
void deleteGradeAll()
{
GradeData *p;
p= pHeader_g;
while(pHeader_g != NULL) //当头部不为空时
{
pHeader_g=p->Pnext; //头部后移
free(p); //释放头部
p=pHeader_g; //p 指向新头部
}
pHeader_g = pTail_g = NULL; //头、尾置空
}
//编辑成绩节点
void editGradeNode(GradeData *pEdited)
{
printf("输入成绩信息:");
inputGradeDataNode(pEdited); //调用函数 输入成绩节点
}
//通过学号和科目 查询到准确的成绩节点
GradeData *findAGradeData()
{
GradeData *p;
int result = 0;
int result1,result2;
char buffer[30];
char buffer1[30];
char buffer2[30];
gets(buffer); //清除缓冲区残留
printf("输入查询学号:");
scanf("%s",&buffer1);
gets(buffer); //清除缓冲区残留
printf("输入查询科目:");
scanf("%s",&buffer2);
p= pHeader_g;
while(p!= NULL && !result) //循环判断,直至p 指向链表尾部
{
result1= strcmp(buffer1,(p->grades.id)); //对输入的学号和 成绩节点中的 学号进行 基于字符串的比较
result2= strcmp(buffer2,(p->grades.subject)); //对输入的科目和 成绩节点中的 科目进行 基于字符串的比较
if(result1 == 0 && result2 == 0) //如果学号和科目相同
{
return p;
}
else //不同时,指针p后移动
{
p = p->Pnext;
}
}
return NULL;
}
//输入学生信息
void inputStudentInformation(StudentInformation *pStudentInfor)
{
char buffer[50]; //用于消除Scanf() 缓存区残留
printf("任意键继续。。。。\n");
gets(buffer);
printf("班级:");
scanf("%s",pStudentInfor->Class);
gets(buffer);
printf("姓名:");
scanf("%s",pStudentInfor->name);
gets(buffer);
printf("学号:");
scanf("%s",pStudentInfor->id);
}
//输入学生节点
void inputStudentNode(Student*pStudentNode)
{
inputStudentInformation(&(pStudentNode->studentinfor));
}
//输出学生信息
void printStudentInformation(StudentInformation *pStuInfor)
{
printf("\n");
printf("\t%s",pStuInfor->Class);
printf("\t%s",pStuInfor->name);
printf("\t%s",pStuInfor->id);
printf("\n");
}
//输出学生节点
void printStudentNode(Student *pStudentNode)
{
printStudentInformation(&(pStudentNode->studentinfor));
}
//输出所有学生节点
void printStudentNodeAll()
{
Student *p= pHeader_s;
if(p == NULL)
{
puts("没有记录\n");
exit(-1);
}
else
{
printf("\t%s\t%s\t%s","班级","姓名","学号");
while(p!= NULL)
{
printStudentNode(p);
p= p->Next;
}
}
}
//在学生尾部添加节点
void addAtStudentTail(Student *pNewNoStudentNode)
{
if(pHeader_s==NULL) //无头时
{
pHeader_s= pTail_s= pNewNoStudentNode;
}
else
{
pTail_s->Next= pNewNoStudentNode;
pTail_s= pNewNoStudentNode;
}
}
//删除学生节点
void deleteStudentNode(Student *pDeleate)
{
Student *p,*q; //学生节点型指针 p, q
p= q= pHeader_s; //p,q 赋值为成绩头指针
while(p!= pDeleate) //找到要删除的学生节点 记为 p
{
q= p; //q 保存 P
p= p->Next; //p 赋值为 p->Next
}
if(p == pHeader_s) //如果是头
{
pHeader_s= p->Next;
}
else if(p == pTail_s) //如果是尾
{
q->Next= NULL;
pTail_s= q;
}
else
{
q->Next= p->Next;
}
free(p);
if(pHeader_s== NULL)
{
pTail_s= NULL;
}
}
//删除所有学生节点
void deleteStudentAll()
{
Student *p;
p= pHeader_s;
while(pHeader_s != NULL) //当头部不为空时
{
pHeader_s=p->Next; //头部后移
free(p); //释放头部
p=pHeader_s; //p 指向新头部
}
pHeader_s = pTail_s = NULL; //头、尾置空
}
//编辑学生节点
void editStudentNode(Student *pEdite)
{
printf("请输入学生信息:\n");
inputStudentNode(pEdite);
}
//通过学生ID查询
Student *findByStudentId()
{
Student *p; //学生节点型指针 *p
int result;
char buffer[30];
gets(buffer); //清除缓冲区残留
printf("输入查询学号:");
scanf("%s",&buffer);
p= pHeader_s;
while(p!= NULL) //循环判断,直至p 指向链表尾部
{
result= strcmp(buffer,(p->studentinfor.id)); //对输入的学号和 学生节点中的 学号进行 基于字符串的比较
if(result == 0 ) //如果学号相同
{
return p;
}
else //不同时,指针p后移动
{
p = p->Next;
}
}
return NULL;
}
Menu.c
/*
编译环境:VS2017\Windows10
作者:smallerXuan
指导:
*/
#include
#include
#include
#include "Menu.h"
#include "StudentInfor.h"
//绘制主菜单
void drawMainMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t学生成绩管理系统 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 系统主界面 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、文件管理 ========== 请按F(f) ##\n");
printf("\t## ##\n");
printf("\t##\t2、数据维护 ========== 请按M(m) ##\n");
printf("\t## ##\n");
printf("\t##\t3、数据查询 ========== 请按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t4、数据统计 ========== 请按C(c) ##\n");
printf("\t## ##\n");
printf("\t##\t5、使用帮助 ========== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t6、退出系统 ========== 请按Q(q) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//主菜单响应
void doMainMenu()
{
int done = 0;
char cmd[2];
openGradeDataFromTextFile(); //从文本读入成绩数据
openStudentDataFromTextFile(); //从文本读入学生数据
system("pause");
while(!done)
{
char buffer[1000];
drawMainMenu(); //绘制主菜单
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'F':
case 'f':
doFileManagementMenu(); //文件管理 子菜单 响应
break;
case 'M':
case 'm':
doDataMaintenanceMenu(); //数据维护 子菜单 响应
break;
case 'S':
case 's':
doDataQueryMenu(); //数据查询 子菜单 响应
break;
case 'C':
case 'c':
doDataCensuMenu(); //数据统计 子菜单 响应
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'Q':
case 'q':
onMenuitemExit(); //在菜单退出
break;
default:
printf("输入有误,请从新输入");
}
}
saveGradeDataInTextFile(); //退出系统默认保存成绩数据
saveStudentDataInTextFile(); //退出系统默认保存学生数据
system("pause");
}
//在菜单退出
void onMenuitemExit()
{
char cmd[2];
if(isModified);
{
puts("数据已修改,是否存盘?");
scanf("%s",cmd);
if(cmd[0]== 'Y' || cmd[0]=='y') //存盘,退出成绩
{
//onMenuitemSave();
saveGradeDataInTextFile(); //保存成绩数据
saveStudentDataInTextFile(); //保存学生数据
system("pause");
exit(0);
}
}
//deleteAll();
deleteStudentAll(); // 删除所有学生节点
deleteGradeAll(); // 删除所有成绩节点
}
//绘制 文件管理 子菜单
void drawFileManagementMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 文件管理 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、导入文件 ========== 请按O(o) ##\n");
printf("\t## ##\n");
printf("\t##\t2、保存文件 ========== 请按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t3、使用帮助 ========== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t4、返回 ========== 请按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//文件管理子菜单响应
void doFileManagementMenu()
{
int done = 0;
char cmd[2];
while(!done)
{ char buffer[1000];
drawFileManagementMenu(); //绘制 文件管理 子菜单
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'O':
case 'o':
openGradeDataFromTextFile(); //从文本读入 成绩 数据
openStudentDataFromTextFile(); //从文本读入 学生 数据
break;
case 'S':
case 's':
saveGradeDataInTextFile(); //保存 成绩 数据 到文本
saveStudentDataInTextFile(); //保存 学生 数据 到文本
system("pause");
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
// 从文本读入成绩数据
void openGradeDataFromTextFile()
{
/*
//随机读写版本
long int q,len, nowfp,diff; //q保存偏移差值,len文件尾偏移量,nowfp当前偏移量, diff偏移差值
long int d=0;
GradeData *newGradeDataNode= NULL;
FILE *inFile= NULL;
deleteGradeAll(); //在读取文本前 清空所有链表节点
inFile= fopen(textGradeDataFile,"rt"); //用fopen()只读打开一个文本文件,只允许读数据
if(inFile==NULL)
{
printf("无法打开文本 %s.txt",textGradeDataFile);
exit(-1);
}
nowfp =ftell(inFile);
fseek(inFile, 0,SEEK_END); //移动文件指针到文件尾部
len =ftell(inFile); //获取当前文件针相对文件首部的偏移量
fseek(inFile, 0,SEEK_SET); //移动文件指针到文件头部
q= nowfp =ftell(inFile); //获取并保存当前偏移量
newGradeDataNode= (GradeData*)malloc(sizeof(GradeData)); //在堆中开辟空间
newGradeDataNode->Pnext= NULL;
fscanf(inFile,"%s%s%f",&(newGradeDataNode->grades).id,&(newGradeDataNode->grades).subject,&(newGradeDataNode->grades).grade);
free(newGradeDataNode); //释放临时存储区
nowfp =ftell(inFile); //获取当前偏移量
diff= nowfp - q + 1; //得到一次读取偏移差值
fseek(inFile, 0,SEEK_SET); //移动文件指针到文件头部
nowfp =ftell(inFile); //获取当前偏移量
//while(!feof(inFile));
if(nowfp== len)
{
printf("\n从文件读入数据\n");
}
while(nowfp <= (len-diff))
{
newGradeDataNode= (GradeData*)malloc(sizeof(GradeData)); //在堆中开辟空间
if(newGradeDataNode ==NULL)
{
puts("内存不足,无法读取数据");
}
else
{
newGradeDataNode->Pnext= NULL;
fscanf(inFile,"%s%s%f",&(newGradeDataNode->grades).id,&(newGradeDataNode->grades).subject,&(newGradeDataNode->grades).grade);
nowfp=ftell(inFile); //更新当前偏移量
addAtGradeTail(newGradeDataNode); //在成绩尾部添加节点
}
d++;
}
fclose(inFile);
printf("\n已读入%d条成绩信息\n",d);
*/
GradeData *newGradeDataNode= NULL;
FILE *inFile= NULL;
int d=0;
deleteGradeAll(); //在读取文本前 清空所有链表节点
inFile= fopen(textGradeDataFile,"rt"); //用fopen()只读打开一个文本文件,只允许读数据
if(inFile==NULL)
{
printf("无法打开文本 %s.txt",textGradeDataFile);
exit(-1);
}
newGradeDataNode= (GradeData*)malloc(sizeof(GradeData)); //在堆中开辟空间
newGradeDataNode->Pnext= NULL;
fscanf(inFile,"%s%s%f",&(newGradeDataNode->grades).id,&(newGradeDataNode->grades).subject,&(newGradeDataNode->grades).grade);
while(!feof(inFile))
{
addAtGradeTail(newGradeDataNode); //在成绩尾部添加节点
newGradeDataNode= (GradeData*)malloc(sizeof(GradeData)); //在堆中开辟空间
newGradeDataNode->Pnext= NULL;
fscanf(inFile,"%s%s%f",&(newGradeDataNode->grades).id,&(newGradeDataNode->grades).subject,&(newGradeDataNode->grades).grade);
d++;
}
free(newGradeDataNode);
fclose(inFile);
printf("已经读入: %d",d);
}
// 保存成绩数据到文本
void saveGradeDataInTextFile()
{
GradeData *p= pHeader_g;
FILE *outFile= NULL;
int d=0;
outFile= fopen(textGradeDataFile,"wt"); //用fopen()只写打开或建立一个文本文件,只允许写数据
if(outFile == NULL)
{
printf("无法打开文本 %s.txt",textGradeDataFile);
}
if(p== NULL)
{
puts("没有记录!");
}
else
{
while(p!= NULL)
{
fprintf(outFile,"%15s%15s%15f\n",p->grades.id,p->grades.subject,p->grades.grade);
p= p->Pnext;
d++;
}
}
fclose(outFile);
printf("成绩数据已保存%d\n",d);
}
//从文本读入 学生数据
void openStudentDataFromTextFile()
{
long int q,len, nowfp,diff; //q保存偏移差值,len文件尾偏移量,nowfp当前偏移量, diff偏移差值
long int d=0;
Student *newStudentDataNode= NULL;
FILE *inFile= NULL;
deleteStudentAll(); //在读取文本前 清空所有链表节点
inFile= fopen(textStudentDataFile,"rt"); //用fopen()只读打开一个文本文件,只允许读数据
if(inFile==NULL)
{
printf("无法打开文本 %d.txt",textStudentDataFile);
exit(-1);
}
nowfp =ftell(inFile);
fseek(inFile, 0,SEEK_END); //移动文件指针到文件尾部
len =ftell(inFile); //获取当前文件针相对文件首部的偏移量
fseek(inFile, 0,SEEK_SET); //移动文件指针到文件头部
q= nowfp =ftell(inFile); //获取并保存当前偏移量
newStudentDataNode= (Student*)malloc(sizeof(Student)); //在堆中开辟空间
newStudentDataNode->Next= NULL;
fscanf(inFile,"%s%s%s",&(newStudentDataNode->studentinfor).Class,&(newStudentDataNode->studentinfor).name,&(newStudentDataNode->studentinfor).id);
free(newStudentDataNode); //释放临时存储区
nowfp =ftell(inFile); //获取当前偏移量
diff= nowfp - q + 1; //得到一次读取偏移差值
fseek(inFile, 0,SEEK_SET); //移动文件指针到文件头部
nowfp =ftell(inFile); //获取当前偏移量
//while(!feof(inFile));
while(nowfp <= (len-diff))
{
newStudentDataNode= (Student*)malloc(sizeof(Student)); //在堆中开辟空间
if(newStudentDataNode ==NULL)
{
puts("内存不足,无法读取数据");
}
else
{
newStudentDataNode->Next= NULL;
fscanf(inFile,"%s%s%s",&(newStudentDataNode->studentinfor).Class,&(newStudentDataNode->studentinfor).name,&(newStudentDataNode->studentinfor).id);
nowfp=ftell(inFile); //更新当前偏移量
addAtStudentTail(newStudentDataNode); //在学生尾部添加节点
}
d++;
}
fclose(inFile);
printf("已读入%d条学生信息\n",d);
}
//保存学生数据到文本
void saveStudentDataInTextFile()
{
Student *p= pHeader_s;
FILE *outFile= NULL;
int d=0;
outFile= fopen(textStudentDataFile,"wt"); //用fopen()只写打开或建立一个文本文件,只允许写数据
if(outFile == NULL)
{
printf("无法打开文本 %s.txt",textStudentDataFile);
}
if(p== NULL)
{
puts("没有记录!");
}
else
{
while(p!= NULL)
{
fprintf(outFile,"%15s%15s%15s\n",p->studentinfor.Class,p->studentinfor.name,p->studentinfor.id);
p= p->Next;
d++;
}
}
fclose(outFile);
printf("\n学生数据已保存%d条\n",d);
}
//绘制 数据维护 子菜单
void drawDataMaintenanceMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 数据维护 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、学生数据维护 ======== 请按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t2、成绩数据维护 ======== 请按G(g) ##\n");
printf("\t## ##\n");
printf("\t##\t4、使用帮助 ======== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ======== 请按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//数据维护 子菜单 响应
void doDataMaintenanceMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataMaintenanceMenu(); //数据维护 子菜单
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'S':
case 's':
doDataMaintenanceMenu_s(); // 数据维护 二级子菜单(学生)响应
break;
case 'G':
case 'g':
doDataMaintenanceMenu_g(); // 数据维护 二级子菜单(成绩)响应
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
// 绘制 数据维护 二级子菜单(学生)
void drawDataMaintenanceMenu_s()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 学生数据维护 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、新增记录 ========== 请按A(a) ##\n");
printf("\t## ##\n");
printf("\t##\t2、修改记录 ========== 请按E(e) ##\n");
printf("\t## ##\n");
printf("\t##\t3、删除记录 ========== 请按D(d) ##\n");
printf("\t## ##\n");
printf("\t##\t4、使用帮助 ========== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 请按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
// 数据维护 二级子菜单(学生)响应
void doDataMaintenanceMenu_s()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataMaintenanceMenu_s(); // 绘制 数据维护 二级子菜单(学生)
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'A':
case 'a':
onMenueitemAddStudent(); //在菜单添加学生记录
break;
case 'E':
case 'e':
onMenuitemEditeStudent(); //在菜单编辑学生
break;
case 'D':
case 'd':
onMenuitemDeleteStudent(); //在菜单删除学生节点
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
// 在菜单添加学生记录
void onMenueitemAddStudent()
{
Student *newNode; //创建新学生节点记录
newNode= (Student*) malloc(sizeof(Student)); //依据学生结构体的数据大小在堆中分配内存
if(newNode == NULL) //当内存分配失败时
{
puts("内存不足,无法创建");
exit(-1);
}
system ("cls");
inputStudentNode(newNode); // 输入学生节点
newNode->Next= NULL;
addAtStudentTail(newNode); // 在学生尾部添加节点
puts("记录添加成功! ");
printStudentNode(pTail_s); // 输出学生节点
system ("pause");
isModified= 1;
}
//在菜单编辑学生
void onMenuitemEditeStudent()
{
Student *pFound;
printf("请输入要编辑的学生的相关信息:\n");
pFound= findByStudentId(); //pFound 为通过学生ID查询到的学生节点
if(pFound != NULL)
{
system("cls");
editStudentNode(pFound); //通过pFound 编辑学生节点
printf("记录已修改 。\n");
printStudentNode(pFound); //打印修改后的学生节点
isModified= 1; //标识修改成功
}
else
{
puts("没有要修改的记录!");
}
system("pause");
}
//在菜单删除学生节点
void onMenuitemDeleteStudent()
{
Student *pFound;
printf("请输入要删除学生的相关信息:\n");
pFound= findByStudentId(); //pFound 为通过学号查询到的结果
if(pFound != NULL)
{
system("cls");
deleteStudentNode(pFound); //通过pFound 删除成绩节点
printf("记录已删除 。\n");
printStudentNodeAll(); //输出所有学生节点
isModified= 1; //标识修改成功
}
else
{
puts("没有要删除的记录!");
}
system("pause");
}
//绘制 数据维护 二级子菜单(成绩)
void drawDataMaintenanceMenu_g()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 成绩数据维护 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、新增记录 ========== 请按A(a) ##\n");
printf("\t## ##\n");
printf("\t##\t2、修改记录 ========== 请按E(e) ##\n");
printf("\t## ##\n");
printf("\t##\t3、删除记录 ========== 请按D(d) ##\n");
printf("\t## ##\n");
printf("\t##\t4、使用帮助 ========== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 请按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//数据维护 二级子菜单(成绩)响应
void doDataMaintenanceMenu_g()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataMaintenanceMenu_g(); //绘制 数据维护 二级子菜单(成绩)
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'A':
case 'a':
onMenueitemAddGrade(); //在菜单添加成绩记录
break;
case 'E':
case 'e':
onMenuitemEditeGrade(); //在菜单编辑成绩
break;
case 'D':
case 'd':
onMenuitemDeleteGrade(); //在菜单删除成绩节点
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
//在菜单添加成绩记录
void onMenueitemAddGrade()
{
GradeData *newNode; //创建新成绩节点记录
newNode= (GradeData*) malloc(sizeof(GradeData)); //依据成绩结构体的数据大小在堆中分配内存
if(newNode == NULL) //当内存分配失败时
{
puts("内存不足,无法创建");
exit(-1);
}
system ("cls");
inputGradeDataNode(newNode); //输入成绩节点信息
newNode->Pnext= NULL;
addAtGradeTail(newNode); //在成绩链表尾部添加
puts("记录添加成功! ");
printGradeDataNode(pTail_g); //输出已添加的成绩节点
system ("pause");
isModified= 1;
}
//在菜单编辑成绩
void onMenuitemEditeGrade()
{
GradeData *pFound= findAGradeData(); //pFound 为通过学号和科目查询到的结果
if(pFound != NULL)
{
system("cls");
editGradeNode(pFound); //通过pFound 编辑成绩节点
printf("记录已修改 。\n");
printGradeDataNode(pFound); //打印修改后的节点
isModified= 1; //标识修改成功
}
else
{
puts("没有要修改的记录!");
}
system("pause");
}
//在菜单删除成绩节点
void onMenuitemDeleteGrade()
{
GradeData *pFound= findAGradeData(); //pFound 为通过学号和科目查询到的结果
if(pFound != NULL)
{
system("cls");
deleteGradeNode(pFound); //通过pFound 删除成绩节点
printf("记录已删除 。\n");
printGradeDataAll(); //输出所有成绩节点
isModified= 1; //标识修改成功
}
else
{
puts("没有要删除的记录!");
}
system("pause");
}
//绘制 数据查询 子菜单
void drawDataQueryMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 数据查询 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、学生数据 ========== 请按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t2、成绩数据 ========== 请按G(g) ##\n");
printf("\t## ##\n");
printf("\t##\t3、使用帮助 ========== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 请按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
// 数据查询 子菜单 响应
void doDataQueryMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataQueryMenu(); //绘制 数据查询 子菜单
printf("任意键继续。\n");
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'S':
case 's':
doStudentDataQueryMenu(); //数据查询 二级子菜单(学生) 响应
break;
case 'G':
case 'g':
doGradeDataQueryMenu(); //数据查询 二级子菜单(成绩) 响应
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
//绘制 数据查询 二级子菜单(学生)
void drawStudentDataQueryMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 学生数据查询 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、浏览数据 ========== 请按B(B) ##\n");
printf("\t## ##\n");
printf("\t##\t2、查找数据 ========== 请按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t3、使用帮助 ========== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 请按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//数据查询 二级子菜单(学生) 响应
void doStudentDataQueryMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawStudentDataQueryMenu(); //绘制 数据查询 二级子菜单(学生)
printf("任意键继续。\n");
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'B':
case 'b':
onMenueitemBrowseStudent(); //在菜单浏览学生数据
break;
case 'S':
case 's':
onMenueitemSearchStudent(); //在菜单查询学生数据
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
//在菜单浏览学生数据
void onMenueitemBrowseStudent()
{
printStudentNodeAll(); // 输出所有学生节点
system("pause");
}
//在菜单查询学生数据
void onMenueitemSearchStudent()
{
Student *pFound;
pFound= findByStudentId(); // pFound为通过学生ID查询到的学生节点
if(pFound != NULL)
{
printStudentNode(pFound); // 输出查询到的学生节点
}
else
{
puts("未查询到相关信息!");
}
system("pause");
}
//绘制 数据查询 二级子菜单(成绩)
void drawGradeDataQueryMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 成绩数据查询 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、浏览数据 ========== 请按B(s) ##\n");
printf("\t## ##\n");
printf("\t##\t2、查找数据 ========== 请按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t3、使用帮助 ========== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t5、返回 ========== 请按R(r) ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//数据查询 二级子菜单(成绩) 响应
void doGradeDataQueryMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawGradeDataQueryMenu(); //绘制 数据查询 二级子菜单(成绩)
printf("任意键继续。\n");
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'B':
case 'b':
onMenueitemBrowseGradeData(); //在菜单浏览成绩数据
break;
case 'S':
case 's':
onMenueitemSearchGradeData(); //在菜单查询成绩数据
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
//在菜单浏览成绩数据
void onMenueitemBrowseGradeData()
{
printGradeDataAll(); // 输出所有成绩节点
system("pause");
}
//在菜单查询成绩数据
void onMenueitemSearchGradeData()
{
GradeData *pFound;
pFound= findAGradeData(); // pFound为通过学生ID和科目查询到的成绩节点
if(pFound != NULL)
{
printGradeDataNode(pFound); // 输出查询到的成绩节点
}
else
{
puts("未查询到相关信息!");
}
system("pause");
}
// 绘制 数据统计 子菜单
void drawDataCensuMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 数据统计 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t1、学生统计 ========== 请按S(s) ##\n");
printf("\t## ##\n");
printf("\t##\t2、使用帮助 ========== 请按H(h) ##\n");
printf("\t## ##\n");
printf("\t##\t3、返回 ========== 请按R(r) ##\n");
printf("\t## ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//数据统计 子菜单 响应
void doDataCensuMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawDataCensuMenu(); // 绘制 数据统计 子菜单
printf("任意键继续。\n");
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'S':
case 's':
onMenueitemStatisticsStudent(); //在菜单统计学生成绩信息
break;
case 'H':
case 'h':
doHelpDocumentMenu(); //帮助文档 子菜单 响应
break;
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
//在菜单统计学生成绩信息
void onMenueitemStatisticsStudent()
{
Student *pFound;
GradeData *p= pHeader_g; //指针指向成绩节的头
char buffer[30];
char buffer1[30];
int result = 0;
float Sumgrade=0.0; //总成绩
float num=0.0; //科目数
gets(buffer); //清除缓冲区残留
printf("输入查询学号:");
scanf("%s",&buffer1);
pFound= findByStudentId(); // pFound为通过学生ID查询到的学生节点
if(pFound != NULL)
{
printStudentNode(pFound); // 输出查询到的学生节点
}
else
{
puts("未查询到相关学生信息!");
}
if(p == NULL)
{
puts("没有成绩记录");
}
while(p!= NULL) //循环判断,直至p 指向链表尾部
{
result= strcmp(buffer1,(p->grades.id)); //对输入的学号和 成绩节点中的 学号进行 基于字符串的比较
if(result == 0 ) //如果学号相同
{
printGradeDataNode(p); // 输出成绩节点
Sumgrade+=p->grades.grade; //成绩增加
num++; //科目数增加
}
p = p->Pnext; //不同时,指针p后移动
}
if(num== 0.0)
num=1.0;
printf("\n\t总成绩:%f\t平均成绩: %f\n",Sumgrade,Sumgrade/num);
system("pause");
}
// 绘制 帮助文档 子菜单
void drawHelpDocumentMenu()
{
system("cls"); //清屏
printf("\n");
printf("\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\t 使用帮助 ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t ##\n");
printf("\t## ##\n");
printf("\t##\t1、请依照界面提示进行相应输入 ##\n");
printf("\t## ##\n");
printf("\t##\t ##\n");
printf("\t##\t2、返回 ========== 请按R(r) ##\n");
printf("\t##\t ##\n");
printf("\t## ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
printf("\t## ##\n");
printf("\t##\t\tMaked By : smallerXuan ##\n");
printf("\t## ##\n");
printf("\t################################################\n");
}
//帮助文档 子菜单 响应
void doHelpDocumentMenu()
{
int done = 0;
char cmd[2];
while(!done)
{
char buffer[1000];
drawHelpDocumentMenu(); // 绘制 帮助文档 子菜单
gets(buffer);
printf("请输入选项:");
scanf("%s",cmd);
switch(cmd[0])
{
case 'R':
case 'r':
done = 1;
break;
default:
printf("输入有误,请从新输入");
}
}
}
StudentAchievementManagementSystemStart.c
/*
编译环境:VS2017\Windows10
作者:smallerXuan
指导:
*/
#include
#include "DataType.h"
#include "StudentInfor.h"
#include "Menu.h"
GradeData *pHeader_g=NULL,*pTail_g=NULL; //成绩链表头、尾
Student *pHeader_s=NULL,*pTail_s=NULL; //学生链表头、尾
char textGradeDataFile[20]= "textGradeDataFile"; //成绩数据文件名称
char textStudentDataFile[20]= "textStudentDataFile"; //学生数据文件名称
int isModified=0; //记录修改是否成功
int main (void)
{
doMainMenu();
return 0;
}