源代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SUBJECT_NUM 3
#define LEN sizeof(struct student)
//student结构体
struct student{
char studentID[11]; // 学号
char name[16]; // 姓名
float score[SUBJECT_NUM]; // 分数,为了方便,设置三科分数
float GPA; // 平均绩点
struct student *next; // 结构体指针
};
int openstyle; //打开文件的方式
int saveTag; // 0表示已保存,1表示未保存
struct student *head; //链表头指针
FILE *fp; //指向打开或者新建文件的文件指针
char filename[10]; // 打开或者新建文件的文件名
char credit[SUBJECT_NUM]; //各科学分
int creditSum; //学分总和
//函数原型
void print();
struct student * open();
struct student * newBuild();
struct student * loadRecords(FILE *fp);
int id_verification();
void enter_menu();
int menu_select();
void inputCredit();
struct student * addRecord();
int unique(char id[11]);
struct student * del();
struct student * ID_delRecord();
struct student * name_delRecord();
struct student * modify();
struct student * ID_modifyRecord();
struct student * name_modifyRecord();
void display();
void displayAll();
void displayFail();
void query();
void ID_query();
void Name_query();
float calculate_GPA(struct student *p);
void GPA_sort();
void saveRecords();
void quit();
void end();
//主函数
void main()
{
print();
if(id_verification()){
//选择操作文件的方式
printf("**************************\n");
printf("* *\n");
printf("* *\n");
printf("* 1. 打开文件 *\n");
printf("* *\n");
printf("* 2. 新建文件 *\n");
printf("* *\n");
printf("* *\n");
printf("**************************\n");
printf("请输入您的选择:\n");
for(;;) {
scanf("%d",&openstyle);
getchar();
if(openstyle>0 && openstyle<3){
break;
}else{
printf("\t输入错误,请重新输入您的选择:\n");
}
}
if(openstyle==1){
head=open();
}else{
head=newBuild();
}
//进入功能菜单
enter_menu();
}
return;
}
//生成系统初始界面
void print()
{
printf("***************************************\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* 学生成绩管理系统 *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* 欢迎使用 *\n");
printf("* *\n");
printf("* *\n");
printf("***************************************\n\n");
}
//管理员身份验证函数
//如果输入三次用户名和密码仍然不能通过验证,那么系统将自动退出
//默认用户名:admin 默认密码:000000
int id_verification()
{
int i;
char user[5];
char userPassword[6];
char *userName="admin"; //默认用户名:admin
char *password="000000"; //默认密码:000000
for(i=1;i<=4;i++){
if(i==4){
printf("身份验证失败\n");
printf("系统已经自动退出\n");
return 0;
}
if(i==1){
printf("请输入用户名:\n");
gets(user);
printf("请输入用户密码:\n");
gets(userPassword);
if(strcmp(user,userName)==0 && strcmp(userPassword,password)==0){
printf("身份验证成功\n\n");
return 1;
}
}else{
printf("用户名与密码不匹配\n");
printf("请重新输入用户名:\n");
gets(user);
printf("请重新输入用户密码:\n");
gets(userPassword);
if(strcmp(user,userName)==0 && strcmp(userPassword,password)==0){
printf("身份验证成功\n\n");
return 1;
}
}
}
}
//打开已经存在的文件 ,并调用加载函数
struct student * open()
{
printf("请输入要打开文件名:\n");
getchar();
gets(filename);
if((fp=fopen(filename,"rb"))==NULL){
printf("can't open file!\n");
exit(0);
}
return loadRecords(fp);
}
//原文件不存在,新建一个文件 ,
struct student * newBuild()
{
printf("请输入新建打开文件名:\n");
getchar();
gets(filename);
if((fp=fopen(filename,"wb"))==NULL){
printf("can't build file!\n");
exit(0);
}
fclose(fp);
return NULL;
}
//加载文件数据,返回一个头结点为head的链表。
//如果文件为空,则返回一个空链表
struct student * loadRecords(FILE *fp)
{
struct student *head=NULL;
struct student *p1,*p2;
while(1){
//从文件中读取数据,并将数据放进一个链表里
if(head==NULL){
p1=p2=(struct student *)malloc(LEN);
fread(p1,LEN,1,fp);
if(feof(fp)){
break;
}
head=p1;
}else{
p1=(struct student *)malloc(LEN);
fread(p1,LEN,1,fp);
if(feof(fp)){
break;
}
p2->next=p1;
p2=p1;
}
}
p2->next=NULL;
fclose(fp);
return (head);
}
//菜单处理函数
void enter_menu()
{
while(1){
switch(menu_select()){
case 1:
inputCredit();
break;
case 2:
head=addRecord();
break;
case 3:
head=del();
break;
case 4:
head=modify();
break;
case 5:
display();
break;
case 6:
query();
break;
case 7:
GPA_sort();
break;
case 8:
saveRecords();
break;
case 9:
quit();
}
}
}
//菜单选择函数
int menu_select()
{
int option;
printf("***************************************\n");
printf("* *\n");
printf("* *\n");
printf("* 系统菜单 *\n");
printf("* *\n");
printf("* 1. 输入各科学分 *\n");
printf("* *\n");
printf("* 2. 添加学生信息 *\n");
printf("* *\n");
printf("* 3. 删除信息 *\n");
printf("* *\n");
printf("* 4. 修改信息 *\n");
printf("* *\n");
printf("* 5. 显示学生信息 *\n");
printf("* *\n");
printf("* 6. 查询学生信息 *\n");
printf("* *\n");
printf("* 7. 根据GPA高低输出学生信息 *\n");
printf("* *\n");
printf("* 8. 保存 *\n");
printf("* *\n");
printf("* 9. 退出系统 *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("***************************************\n\n");
printf("请输入您的选择:\n");
for(;;) {
scanf("%d",&option);
getchar();
if(option>0 && option<10){
return option;
}else{
printf("\t输入错误,请重新输入您的选择:\n");
}
}
}
//输入各科学分 ,并计算学分总和
void inputCredit()
{
int i=1;
creditSum=0;
//先输入各科学分
for(i=1;i<=SUBJECT_NUM;i++){
printf("请输入第%d科的学分:\n",i);
scanf("%d",&credit[i-1]);
}
//求出各科学分之和
for(i=1;i<=SUBJECT_NUM;i++){
creditSum=creditSum+credit[i-1];
}
}
//向链表中添加新的数据
//返回更新数据之后的链表头结点
//学号必须唯一
struct student * addRecord()
{
//用于判断是否和已经添加的学号相同
char testID[11];
//newRecord 是新添加的数据指针
struct student *p,*newRecord;
//将指针p 指向最后一个结点
p=head;
if(head!=NULL){
while(p->next!=NULL){
p=p->next;
}
}
//向指针p后面添加新的数据
char str[5];
int j;
while(1){
printf("您将要添加一组新的信息,确定吗?\n");
printf(" (Y/N) \n");
gets(str);
//如果选择no,不再添加新的
if(str[0]=='n' || str[0]=='N') {
break;
}
//输入新结点的信息
newRecord=(struct student *)malloc(LEN);
printf("请输入学号:\n");
gets(testID);
while(1){
if(unique(testID)){
strcpy(newRecord->studentID,testID);
break;
}
else{
printf("学号已存在,请重新输入!\n");
gets(testID);
}
}
printf("请输入姓名:\n");
gets(newRecord->name);
for(j=1;j<=SUBJECT_NUM;j++){
printf("请输入第%d科成绩:\n",j);
scanf("%f",&(newRecord->score[j-1]));
getchar();
}
//计算newRecord的GPA
newRecord->GPA=calculate_GPA(newRecord);
if(head==NULL){
head=newRecord;
}
else{
p->next=newRecord;
}
p=newRecord;
}
if(head!=NULL){
p->next=NULL;
}
saveTag=1;
return (head);
}
//判断学号是否唯一,唯一返回1,不唯一返回0
int unique(char id[11]){
struct student *p;
if(head==NULL){
return 1;
}
else{
p=head;
do{
if(strcmp(id,p->studentID)==0){
return 0;
}
p=p->next;
}while(p!=NULL);
return 1;
}
}
//删除信息
struct student * del()
{
int delStyle;
char str[5];
while(1){
printf("**************************\n");
printf("* *\n");
printf("* *\n");
printf("* 1. 学号删除 *\n");
printf("* *\n");
printf("* 2. 姓名删除 *\n");
printf("* *\n");
printf("* *\n");
printf("**************************\n");
printf("请输入您的选择:\n");
while(1){
scanf("%d",&delStyle);
getchar();
if(delStyle>0 && delStyle<3){
break;
}else{
printf("输入错误,请重新输入您的选择:\n");
}
}
if(delStyle==1){
head=ID_delRecord();
}
else if(delStyle==2){
head=name_delRecord();
}
//提示是否要删除信息
printf("是否还要删除信息?\n");
printf(" (Y/N) \n");
gets(str);
//选择no,停止删除信息
if(str[0]=='n' || str[0]=='N') {
break;
}
}
return (head);
}
// 删除链表中指定的结点
//根据学号删除链表中的结点
struct student * ID_delRecord()
{
struct student *p1,*p2;
//存储待删学生的学号
char targetID[11];
//如果为空表,函数结束
if(head==NULL){
printf("无信息,请先添加数据\n");
return (head);
}
//输入待删的学号
printf("请输入要删除的学生的学号:\n");
gets(targetID);
p1=head;
//从头遍历链表,直到找到该学号,或者直到链表结束
while(strcmp(targetID,p1->studentID)!=0 && p1->next!=NULL){
p2=p1;
p1=p1->next;
}
//如果找到该生
if(strcmp(targetID,p1->studentID)==0){
if(p1==head) head=p1->next; //头结点为要删除的信息
else p2->next=p1->next; //头结点不是要删除的信息
printf("删除的学生信息学号是:%s\n\n",targetID);
free(p1);
printf("删除成功!\n\n");
}
else{
printf("该生信息不存在!\n\n"); //未找到该生信息
}
saveTag=1;
return (head);
}
//根据学生姓名删除信息
struct student * name_delRecord()
{
struct student *p1,*p2;
//存储待删学生的姓名
char targetname[16];
//如果为空表,函数结束
if(head==NULL){
printf("无信息,请先添加数据\n");
return (head);
}
//输入待删的姓名
printf("请输入要删除的学生的姓名:\n");
gets(targetname);
getchar();
p1=head;
//从头遍历链表,直到找到该姓名,或者直到链表结束
while(strcmp(targetname,p1->name)!=0 && p1->next!=NULL){
p2=p1;
p1=p1->next;
}
//如果找到该生
if(strcmp(targetname,p1->name)==0){
if(p1==head) head=p1->next; //头结点为要删除的信息
else p2->next=p1->next; //头结点不是要删除的信息
printf("删除的学生信息姓名是:%s\n\n",targetname);
free(p1);
printf("删除成功!\n\n");
}
else{
printf("该生信息不存在!\n\n"); //未找到该生信息
}
saveTag=1;
return (head);
}
//修改信息
struct student * modify()
{
int modifyStyle;
char str[5];
while(1){
printf("**************************\n");
printf("* *\n");
printf("* *\n");
printf("* 1. 学号修改 *\n");
printf("* *\n");
printf("* 2. 姓名修改 *\n");
printf("* *\n");
printf("* *\n");
printf("**************************\n");
printf("请输入您的选择:\n");
while(1){
scanf("%d",&modifyStyle);
getchar();
if(modifyStyle>0 && modifyStyle<3){
break;
}else{
printf("输入错误,请重新输入您的选择:\n");
}
}
if(modifyStyle==1){
head=ID_modifyRecord();
}
else if(modifyStyle==2){
head=name_modifyRecord();
}
//提示是否修改信息
printf("是否还要修改其他学生成绩信息?\n");
printf(" (Y/N) \n");
gets(str);
//选择no,停止修改成绩信息
if(str[0]=='n' || str[0]=='N') {
break;
}
}
return (head);
}
// 修改学生信息
// 输入学号,找到该生信息,并修改其成绩
struct student * ID_modifyRecord()
{
struct student *p1,*p2;
//存储待修改学生的学号
char targetID[11];
char str[5];
//如果为空表,函数结束
if(head==NULL){
printf("无信息,请先添加数据\n");
return (head);
}
//输入待修改的学号
printf("请输入要修改成绩学生的学号:\n");
gets(targetID);
p1=head;
//从头遍历链表,直到找到该学号,或者直到链表结束
while(strcmp(targetID,p1->studentID)!=0 && p1->next!=NULL){
p2=p1;
p1=p1->next;
}
//如果找到该生
if(strcmp(targetID,p1->studentID)==0){
int k;
while(1){
printf("您想修改第几科成绩:\n");
scanf("%d",&k);
if(k>=1 && k<=SUBJECT_NUM){
printf("请输入修改后的成绩: \n");
scanf("%f",&(p1->score[k-1]));
getchar();
printf("修改成功!\n\n");
printf("是否还要修改该生成绩信息?\n");
printf(" (Y/N) \n\n");
gets(str);
//选择no,停止修改该生成绩信息
if(str[0]=='n' || str[0]=='N') {
break;
}
}else{
printf("输入错误,请重新输入!\n");
}
}
//修改完成绩,GPA相应修改
p1->GPA=calculate_GPA(p1);
}
else{
printf("该生信息不存在!\n\n"); //未找到该生信息
}
saveTag=1;
return (head);
}
// 修改学生信息
// 输入姓名,找到该生信息,并修改其成绩
struct student * name_modifyRecord()
{
struct student *p1,*p2;
//存储待修改学生的姓名
char targetname[16];
char str[5];
//如果为空表,函数结束
if(head==NULL){
printf("无信息,请先添加数据\n");
return (head);
}
//输入待修改的姓名
printf("请输入要修改成绩学生的姓名:\n");
gets(targetname);
p1=head;
//从头遍历链表,直到找到该姓名,或者直到链表结束
while(strcmp(targetname,p1->name)!=0 && p1->next!=NULL){
p2=p1;
p1=p1->next;
}
//如果找到该生
if(strcmp(targetname,p1->name)==0){
int k;
while(1){
printf("您想修改第几科成绩:\n");
scanf("%d",&k);
if(k>=1 && k<=SUBJECT_NUM){
printf("请输入修改后的成绩: \n");
scanf("%f",&(p1->score[k-1]));
getchar();
printf("修改成功!\n\n");
printf("是否还要修改该生其他成绩?\n");
printf(" (Y/N) \n\n");
gets(str);
//选择no,停止修改该生成绩信息
if(str[0]=='n' || str[0]=='N') {
break;
}
}else{
printf("输入错误,请重新输入!\n");
}
}
//修改完成绩,GPA相应修改
p1->GPA=calculate_GPA(p1);
}
else{
printf("该生信息不存在!\n\n"); //未找到该生信息
}
saveTag=1;
return (head);
}
//显示信息
void display()
{
int displayStyle;
printf("**************************\n");
printf("* *\n");
printf("* *\n");
printf("* 1. 显示不及格学生 *\n");
printf("* *\n");
printf("* 2. 显示所有学生 *\n");
printf("* *\n");
printf("* *\n");
printf("**************************\n");
printf("请输入您的选择:\n");
while(1){
scanf("%d",&displayStyle);
getchar();
if(displayStyle>0 && displayStyle<3){
break;
}else{
printf("输入错误,请重新输入您的选择:\n");
}
}
if(displayStyle==1){
displayFail();
}
else if(displayStyle==2){
displayAll();
}
}
//显示链表当前内存里所有的信息
void displayAll()
{
struct student *p;
p=head;
//如果链表为空,给出提示
if(p==NULL){
printf("无学生信息,请先输入!\n");
return;
}
else{
//链表不为空,输出所有信息
printf("These records are: \n");
printf("ID\tNAME\tMATH\tENGLISH\t C\tGPA\n\n");
do{
printf("%s\t%s\t%.1f\t%.1f\t %.1f\t%.3f\n",p->studentID,p->name,p->score[0],p->score[1],p->score[2],p->GPA);
p=p->next;
}while(p!=NULL);
}
}
//输出当前内存链表中所有不及格的学生信息
void displayFail()
{
struct student *p;
p=head;
//如果链表为空,给出提示
if(p==NULL){
printf("无学生信息,请先输入!\n");
return;
}
else{
//链表不为空,输出所有不及格学生信息
printf("不及格学生信息:\n");
printf("ID\tNAME\tMATH\tENGLISH\t C\tGPA\n\n");
do{
//判断学生是否有不及格的成绩
//当三科中有一科成绩满足条件就输出
if((p->score[0]<60) || (p->score[1]<60) || (p->score[2]<60)){
printf("%s\t%s\t%.1f\t%.1f\t %.1f\t%.3f\n",p->studentID,p->name,p->score[0],p->score[1],p->score[2],p->GPA);
}
p=p->next;
}while(p!=NULL);
}
}
//查询信息
void query()
{
int queryStyle;
char str[5];
while(1){
printf("**************************\n");
printf("* *\n");
printf("* *\n");
printf("* 1. 学号查询 *\n");
printf("* *\n");
printf("* 2. 姓名查询 *\n");
printf("* *\n");
printf("* *\n");
printf("**************************\n");
printf("请输入您的选择:\n");
while(1){
scanf("%d",&queryStyle);
getchar();
if(queryStyle>0 && queryStyle<3){
break;
}else{
printf("输入错误,请重新输入您的选择:\n");
}
}
if(queryStyle==1){
ID_query();
}
else if(queryStyle==2){
Name_query();
}
//提示是否查询信息
printf("是否还要查询其他学生成绩信息?\n");
printf(" (Y/N) \n");
gets(str);
//选择no,停止查询信息
if(str[0]=='n' || str[0]=='N') {
break;
}
}
}
//根据学生学号查询学生信息
void ID_query()
{
struct student *p1,*p2;
//存储待查学生的学号
char id[11];
//如果为空表,函数结束
if(head==NULL){
printf("无信息,请先添加数据\n");
return;
}
//输入待查的学号
printf("请输入要查询的学生的学号:\n");
gets(id);
p1=head;
//从头遍历链表,直到找到该学号,或者直到链表结束
while(strcmp(id,p1->studentID)!=0 && p1->next!=NULL){
p2=p1;
p1=p1->next;
}
//如果找到该生
if(strcmp(id,p1->studentID)==0){
printf("该生信息如下: \n");
printf("ID\tNAME\tMATH\tENGLISH\t C\tGPA\n\n");
printf("%s\t%s\t%.1f\t%.1f\t %.1f\t%.3f\n",p1->studentID,p1->name,p1->score[0],p1->score[1],p1->score[2],p1->GPA);
}
else{
printf("该生信息不存在!\n"); //未找到该生信息
}
}
//根据学生姓名查询学生信息
void Name_query()
{
struct student *p1,*p2;
//存储待查学生的姓名
char name[16];
//如果为空表,函数结束
if(head==NULL){
printf("无信息,请先添加数据\n");
return;
}
//输入待查的姓名
printf("请输入要查询的学生的姓名:\n");
gets(name);
p1=head;
//从头遍历链表,直到找到该姓名,或者直到链表结束
while(strcmp(name,p1->name)!=0 && p1->next!=NULL){
p2=p1;
p1=p1->next;
}
//如果找到该生
if(strcmp(name,p1->name)==0){
printf("该生信息如下: \n");
printf("ID\tNAME\tMATH\tENGLISH\t C\tGPA\n\n");
printf("%s\t%s\t%.1f\t%.1f\t %.1f\t%.3f\n",p1->studentID,p1->name,p1->score[0],p1->score[1],p1->score[2],p1->GPA);
}
else{
printf("该生信息不存在!\n"); //未找到该生信息
}
}
//计算学生的平均绩点
// 采用的计算公式:GPA=Σ(该科成绩*该科学分) *4/Σ(各科学分)/100
float calculate_GPA(struct student *p)
{
int i=1;
//保存学生成绩与学分乘积之和
float sum;
sum=0.0;
//计算学生的sum
for(i=1;i<=SUBJECT_NUM;i++){
sum=sum+p->score[i-1]*credit[i-1];
}
p->GPA=sum*4/creditSum/100;
return (p->GPA);
}
// 根据学生的GPA由高到低排序
//排序完成后,输出结果
void GPA_sort()
{
int i=1;
//q指向p的前一个结点
struct student *p,*q,*p1,*p2;
//链表为空,提示,结束函数
if(head==NULL){
printf("无信息,请先输入!\n");
return;
}
//链表至少有2条数据
if(head->next!=NULL)
{
//从第二个结点开始排序
q=head;
p=head->next;
do{
p1=head;
//先判断是否插入到头结点之前
if((p->GPA)>(p1->GPA)){
q->next=p->next;
p->next=head;
head=p;
}
//如果不是插入到头结点前
else{
p2=head->next;
//找到要插入的位置
while(p2!=p && (p->GPA)<=(p2->GPA)){
p1=p2;
p2=p2->next;
}
//判断是否需要插入
if(p2!=p){
q->next=p->next;
p->next=p2;
p1->next=p;
}
}
q=p;
p=p->next;
}while(p!=NULL);
}
//排序完成,输出排序后的结果
printf("排序如下:\n");
printf("ID\tNAME\tGPA\trank\n\n");
p=head;
do{
printf("%s\t%s\t%.3f\t%d\n",p->studentID,p->name,p->GPA,i);
i++;
p=p->next;
}while(p!=NULL);
saveTag=1;
}
//保存信息到文件中
void saveRecords(){
//文件保存方式
int saveStyle;
struct student *p;
printf("**************************\n");
printf("* *\n");
printf("* *\n");
printf("* 1. 保存文件 *\n");
printf("* *\n");
printf("* 2. 另存文件 *\n");
printf("* *\n");
printf("* *\n");
printf("**************************\n");
printf("请输入您的选择:\n");
for(;;) {
scanf("%d",&saveStyle);
if(saveStyle>0 && saveStyle<3){
break;
}else{
printf("\t输入错误,请重新输入您的选择:\n");
}
}
//保存文件
if(saveStyle==1){
if((fp=fopen(filename,"wb"))==NULL){
printf("can't open file!\n");
exit(0);
}
if(head==NULL){
printf("无信息,无需保存\n");
return;
}
p=head;
do{
fwrite(p,LEN,1,fp);
p=p->next;
}while(p!=NULL);
printf("数据保存成功\n");
fclose(fp);
}
//另存文件
else if(saveStyle==2){
char newfile[10];
printf("请输入新文件名:\n");
gets(newfile);
if((fp=fopen(newfile,"wb"))==NULL){
printf("can't open file!\n");
exit(0);
}
if(head==NULL){
printf("无信息,无需保存\n");
return;
}
p=head;
do{
fwrite(p,LEN,1,fp);
p=p->next;
}while(p!=NULL);
printf("数据保存成功\n");
fclose(fp);
}
saveTag=0;
}
//退出系统
void quit(){
char str[5];
//saveTag 等于1,表示信息未保存。
if(saveTag==1){
printf("是否保存原来的信息?\n");
printf(" (Y/N) \n");
gets(str);
if(str[0]!='n' && str[0]!='N'){
saveRecords();
}
}
end();
free(head);
exit(0);
}
//结束界面
void end(){
printf("***************************************\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* 感 谢 使 用 !!! *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("* *\n");
printf("***************************************\n");
}