目录
该代码易于扩展,如果要修改学科数量,直接改开头的宏变量就行。
流程图后补
题目如下:
运行截图:
主界面
成绩统计
模糊检索
结构体以及链
表操作
代码如下:
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 3
char *disciplines[N]={"高数","英语","量子力学"};
typedef struct
{
char no[10];
char name[20];
int Class;
int height;
int weight;
int grade[N];
char address[30];
char telNum[12];
char QQ[20];
char speciality[20];
int rank;
char teachName[20] ;
char teachNum[11];
} student;
typedef struct Node //链表结点
{
student stu;
struct Node* next;
} Node,*LinkNode;
/* 可分以下三个模块完成功能的设计
1.链表操作
2.文件操作
3.学生学情信息操作
*/
//-------------链表操作begin-------------
void Initial(LinkNode &L) //初始化链表头结点
{
L=new Node;
L->next=NULL;
}
void Destory(LinkNode &L) //3.销毁单链表
{
while(L)
{ //L-next为空时,当前的L没办法释放,所以是L
LinkNode p = L;
L = L->next;
delete p;
}
}
void add(LinkNode &L,student s) //插入到首元素
{
LinkNode p=new Node;
p->stu=s;
p->next=L->next;
L->next=p; //插入到链表中
}
bool existNumber(char *s) //检查(名字)字符串中是否含有数字
{
int len=strlen(s);
int i;
for(i=0;i<len;i++)
if(s[i]>='0' && s[i]<='9')
return true;
return false;
}
bool isMatched(char *t,char *key) //模糊查询算法 查看目标字符串中是否含有关键词key
{ //字符串支持 下标读取 欧耶!!
//为了简便
//关键词是连续的字符串子序列,没有分开的情况 比如key中 tech ,目标串中不需要考虑tec#h
int n=strlen(t);
int m=strlen(key);
int i=0,j=0;
int count=0;
if(n>=m) //key串长度大于目标串时 没有比较的需要
{ //模式串匹配 暴力搜索
while(i<n && j<m)
{
count++;
if(t[i]==key[j])
{
j++;
i++;
}
else
{
i++;
j=0;
if(i > n-m)
break;
}
if(j==m)
return true;
}
}
return false;
}
void sort(LinkNode &L) //按照学号排序 算法:直接选择排序
{
LinkNode first,min,p;
for(first=L->next ; first->next ; first=first->next) //first下一结点不为空,说明至少有两个元素,则继续排序
{
min=first;
for(p = first ; p ; p=p->next)
if( strcmp(min->stu.no,p->stu.no) >0 )
min=p;
student temp=min->stu; //交换数据域
min->stu = first->stu;
first->stu = temp;
}
}
void SortIntel(LinkNode &L) //按照智育排名排序
{
LinkNode first,min,p;
for(first=L->next ; first->next ; first=first->next) //first下一结点不为空,说明至少有两个元素,则继续排序
{
min=first;
for(p = first ; p ; p=p->next)
if( min->stu.rank > p->stu.rank)
min=p;
student temp=min->stu; //交换数据域
min->stu = first->stu;
first->stu = temp;
}
}
//-------------链表操作end-------------------
//-------------文件操作begin-----------------
void readFrom(char *filename,LinkNode &L) //文件读取到链表上
{
FILE *fp;
fp=fopen(filename,"r"); //读文件
if(fp==0)
{
printf("文件打开失败!");
}
else
{
LinkNode p=L;
while(!feof(fp)) //指针不到末尾
{
p->next=new Node;
p=p->next;
fscanf(fp,"%12s %12s %5d %5d %5d",p->stu.no,p->stu.name,&p->stu.Class,&p->stu.height,&p->stu.weight);
int i;
for(i=0;i<N;i++)
fscanf(fp,"%5d",&p->stu.grade[i]);
fscanf(fp,"%12s %13s %12s %12s",p->stu.address,p->stu.telNum,p->stu.QQ,p->stu.speciality);
fscanf(fp,"%5d %12s %12s\n",&p->stu.rank,p->stu.teachName,p->stu.teachNum);
}
p->next=NULL; //链表的尾结点的next指向NULL
}
fclose(fp);
}
void WriteAdd(char *filename,student s) //添加的信息 以添加的方式写入文件
{
FILE *fp;
fp=fopen(filename,"a+");
if(fp==0)
{
printf("文件打开失败!");
}
else
{
fprintf(fp,"%12s %12s %5d %5d %5d",s.no,s.name,s.Class,s.height,s.weight);
int i;
for(i=0;i<N;i++)
fprintf(fp,"%5d",s.grade[i]);//N门课的成绩
fprintf(fp,"%12s %13s %12s %12s",s.address,s.telNum,s.QQ,s.speciality) ;
fprintf(fp,"%5d %12s %12s\n",s.rank,s.teachName,s.teachNum);
printf("存入一条记录到文件");
}
fclose(fp);
}
void WriteTo(char *filename,LinkNode &L) //链表元素存放在文件中 修改删除 覆盖式写入
{
LinkNode p=L->next;
FILE *fp;
fp=fopen(filename,"w+");
if(fp==0)
{
printf("文件打开失败!");
}
else
{
while(p)
{
fprintf(fp,"%12s %12s %5d %5d %5d",p->stu.no,p->stu.name,p->stu.Class,p->stu.height,p->stu.weight);
int i;
for(i=0;i<N;i++)
fprintf(fp,"%5d",p->stu.grade[i]);//N门课的成绩
fprintf(fp,"%12s %12s %12s %12s",p->stu.address,p->stu.telNum,p->stu.QQ,p->stu.speciality) ;
fprintf(fp,"%5d %12s %12s\n",p->stu.rank,p->stu.teachName,p->stu.teachNum);
p=p->next;
}
}
fclose(fp);
}
//-------------文件操作end-------------------
//-------------学生信息操作begin-------------
void printRow()
{
printf("学号\t 姓名 班级 身高 体重 ");
int i;
for(i=0;i<N;i++)
printf("%-5s",disciplines[i]);
printf("\t地址 电话号码 QQ 特长 智育排名 教师姓名 教师手机号\n");
}
void addStudent(char *filename)
{
student s;
printf("请输入以下信息:\n"); //getchar();
printf("学号:"); scanf("%s",s.no); //getchar();
printf("姓名:"); scanf("%s",s.name); //getchar();
while(true)
{
if(existNumber(s.name))
{
printf("名字中有数字,请重新输入:");
scanf("%s",s.name);
}
else
break;
}
printf("班级:"); scanf("%d",&s.Class); //getchar();
printf("身高:"); scanf("%d",&s.height); //getchar();
printf("体重:"); scanf("%d",&s.weight);
int i;
for(i=0;i<N;i++)
{
while(1)
{
printf("%s:",disciplines[i]);
scanf("%d",&s.grade[i]);
if( s.grade[i]<0 || s.grade[i]>100)
{
printf("成绩输入有误,分数=%d,请重新输入:",s.grade[i]);
scanf("%d",&s.grade[i]);
}
else
break;
}
}
getchar();
printf("家庭住址:"); scanf("%s",s.address); //getchar();
printf("联系电话:"); scanf("%s",s.telNum); //getchar();
printf("QQ:"); scanf("%s",s.QQ); //getchar();
printf("特长:"); scanf("%s",s.speciality);//getchar();
printf("智育排名:"); scanf("%d",&s.rank); //getchar();
printf("任课教师姓名:"); scanf("%s",s.teachName);//getchar();
printf("任课教师手机号:"); scanf("%s",s.teachNum);
WriteAdd(filename,s); //将L中的元素添加到文件
}
void updateStudent(student *s)
{
printf("请输入要修改的内容:\n");
printf("1、班级\t2、身高\t3、体重\t4、成绩\t5、家庭地址\t6、联系电话\n");
printf("7、QQ\t8、特长\t9、智育排名\t10、任课教师姓名\t11、任课教师手机号\n");
printf("请输入序号:");
int no;
scanf("%d",&no);
switch(no)
{
case 1: printf("班级:"); scanf("%d",&s->Class);
break;
case 2: printf("身高:"); scanf("%d",&s->height);
break;
case 3: printf("体重:"); scanf("%d",&s->weight);
break;
case 4: int i;
for(i=0;i<N;i++) //修改成绩
printf("%d %-5s",i+1,disciplines[i]);
printf("请选择要修改的成绩序号:");
int choose;
scanf("%d",&choose);
while(1)
{
if(choose <1 || choose>N)
{
printf("序号输入错误,请重新输入:");
scanf("%d",&choose);
}
else
break; //没有错误就继续
}
printf("原来成绩为:%d ,",s->grade[choose-1]);
printf("要修改为:"); scanf("%d",&s->grade[choose-1]);
break;
case 5: printf("家庭住址:"); scanf("%s",s->address);
break;
case 6: printf("联系电话:"); scanf("%s",s->telNum);
break;
case 7: printf("QQ:"); scanf("%s",s->QQ);
break;
case 8: printf("特长:"); scanf("%s",s->speciality);
break;
case 9: printf("智育排名:"); scanf("%d",&s->rank);
break;
case 10: printf("任课教师姓名:"); scanf("%s",s->teachName);
break;
case 11: printf("任课教师手机号:"); scanf("%s",s->teachNum);
break;
}
}
void addAll(char *filename)
{
int iskeep=1;
while(iskeep==1)
{
iskeep=0;
addStudent(filename);
printf("是否继续录入? \n输入1表示继续 输入0表示退出:");
scanf("%d",&iskeep);
}
}
void dispStu(student s)
{
printf("%-10s %-8s %-5d %-5d %-5d",s.no,s.name,s.Class,s.height,s.weight);
int i;
for(i=0;i<N;i++)
printf("%-5d",s.grade[i]);
printf("\t%-10s %-12s%-11s %-10s",s.address,s.telNum,s.QQ,s.speciality);
printf("%-8d %-12s %-10s\n",s.rank,s.teachName,s.teachNum);
}
void dispAll(char *filename)
{
LinkNode L;
Initial(L);
readFrom(filename,L);
sort(L) ; //先对信息进行按学号排序
LinkNode p=L->next;
printRow();
while(p) //打印链表中所有的学生信息
{
dispStu(p->stu); //每次迭代显示一条学生信息
p=p->next;
}
Destory(L); //销毁链表,回收内存
}
void update(char *filename)
{ //找到要修改的,修改结点的数据域,然后把链表所有元素 覆盖式地存入文件
LinkNode L;
Initial(L);
readFrom(filename,L); //读取文件,存到链表
printf("请在以下2项中选择一项检索\n");
printf("1 学号 2 姓名\n");
printf("请输入序号:");
int choose;
scanf("%d",&choose);
while(true)
{
if(choose <1 || choose >3)
{
printf("输入有误,请再次输入:");
scanf("%d",&choose);
}
else
break;
}
LinkNode p=L->next ;//指向头结点
switch(choose) //遍历链表每个结点,
{
case 1: //比较学号
printf("请输入学号:");
char no[9];
getchar();
gets(no);
printRow(); //打印 列名
while(p)
{
if(strcmp(p->stu.no,no)==0)
{
dispStu(p->stu);
updateStudent(&p->stu);
break; //若撤掉break,则可以输出所有匹配的学生信息
}
p=p->next;
}
break;
case 2:
printf("请输入姓名:");
char name[20];
getchar();
gets(name);
while(p)
{
if(strcmp(p->stu.name,name)==0)
{
dispStu(p->stu);
updateStudent(&p->stu);
break;//若撤掉break,则可以输出所有匹配的学生信息
}
p=p->next;
}
break;
default:printf("序号输入错误!\n");
}
WriteTo(filename,L); //覆盖式写入文件 达到修改信息的效果
Destory(L); //销毁链表,回收内存
}
void delStu(char *filename) //删除与学号相匹配的
{
LinkNode L;
Initial(L);
readFrom(filename,L); //读取文件,存到链表
printf("请在以下2项中选择一项检索\n");
printf("1 学号 2 姓名\n");
printf("请输入序号:");
int choose;
scanf("%d",&choose);
while(true)
{
if(choose <1 || choose >2)
{
printf("输入有误,请再次输入:");
scanf("%d",&choose);
}
else
break;
}
char no[11],name[12];
switch(choose)
{
case 1:printf("请输入学号:"); scanf("%s",no);break;
case 2:printf("请输入姓名:"); scanf("%s",name);break;
}
while(true)
{
readFrom(filename,L); //读取文件,存到链表
LinkNode p=L->next,front=L;
while(p)
{
if( choose==1? strcmp(p->stu.no,no)==0 : strcmp(p->stu.name,name)==0 )
{
printf("已找到,该学生信息为: \n");
printRow();
dispStu(p->stu);
printf("是否删除该学生信息,若删除,输入1,否则输入0 :");
int isDel=1;
scanf("%d",&isDel);
if(isDel)
{
front->next=p->next;
delete p; //删除结点,释放内存
p=front->next;
}
break;
}
else
{
front=front->next;
p=p->next;
}
}
int iskeep;
printf("是否继续删除?若继续则输入1,否则输入0 :");
scanf("%d",&iskeep);
if(iskeep!=1)
break;
}
// 以下覆盖写入文件中,达到删除学生信息的效果
WriteTo(filename,L);
Destory(L); //销毁链表,回收内存
}
void search(char *filename) //返回找到的
{
LinkNode L;
Initial(L);
readFrom(filename,L);
printf("请在以下三项中选择一项检索\n");
printf("1 学号 2 姓名\n3手机号\n");
printf("请输入序号:");
int choose;
scanf("%d",&choose);
while(true)
{
if(choose <1 || choose >3)
{
printf("输入有误,请再次输入:");
scanf("%d",&choose);
}
else
break;
}
LinkNode p=L->next ;//指向头结点
switch(choose) //遍历链表每个结点,
{
case 1: //比较学号
printf("请输入学号:");
char no[9];
getchar();
gets(no);
printRow(); //打印 列名
while(p)
{
if(isMatched(p->stu.no,no))
{
dispStu(p->stu);
break; //若撤掉break,则可以输出所有匹配的学生信息
}
p=p->next;
}
break;
case 2:
printf("请输入姓名:");
char name[10];
getchar();
gets(name);
printRow(); //打印 列名
while(p)
{
if(isMatched(p->stu.name,name))
{
dispStu(p->stu);
break;//若撤掉break,则可以输出所有匹配的学生信息
}
p=p->next;
}
break;
case 3:
printf("请输入手机号:");
char num[10];
getchar();
scanf("%s",num);
printRow(); //打印 列名
while(p)
{
if(isMatched(p->stu.telNum,num))
{
dispStu(p->stu);
break;//若撤掉break,则可以输出所有匹配的学生信息
}
p=p->next;
}
break;
default:printf("序号输入错误!\n");
}
Destory(L); //销毁链表,回收内存
}
void scoresSTATIC( char *filename)
{
LinkNode L;
Initial(L);
readFrom(filename,L); //读取文件,存到链表
LinkNode p=L->next;
int maxScore[N];
int minScore[N];
float avgScore[N];
int pass[N];
int i;
int num=0;
if(p)
{
for(i=0;i<N;i++)
{
minScore[i]=p->stu.grade[i];
maxScore[i]=p->stu.grade[i];
avgScore[i]=0;
pass[i]=0;
}
}
printRow(); //打印 列名
while(p) //打印链表中所有的学生信息
{
for(i=0;i<N;i++)
{
avgScore[i]+=p->stu.grade[i];
p->stu.grade[i]< minScore[i] ? minScore[i]=p->stu.grade[i] : 1 ; // 1用来占位
p->stu.grade[i]> maxScore[i] ? maxScore[i]=p->stu.grade[i] : 1 ; // 1用来占位
p->stu.grade[i]> 60 ? pass[i]++ : 1 ;
}
dispStu(p->stu); //每次迭代显示一条学生信息
p=p->next;
num++; //学生人数
}
if(num>0) //及格人数+不及格人数=总人数
{
for(i=0;i<N;i++)
{
avgScore[i]=avgScore[i]/num;
}
}
printf("-------------------------------------------------统计分析--------------------------------------------------");
printf("\n\t及格人数 不及格人数\t及格率\t平均成绩 最高分\t最低分\n");
for(i=0;i<N;i++)
{
printf("%-8s",disciplines[i]);
printf("%-12d %-12d %-8.2f %-10.2f %-10d %-10d \n",pass[i],num-pass[i],(pass[i]*1.0)/num ,avgScore[i],maxScore[i],minScore[i]) ;
}
Destory(L); //销毁链表,回收内存
}
void intelSort(char *filename)
{
LinkNode L;
Initial(L);
readFrom(filename,L);
SortIntel(L) ; //先对信息进行按学号排序
LinkNode p=L->next;
while(p) //打印链表中所有的学生信息
{
dispStu(p->stu); //每次迭代显示一条学生信息
p=p->next;
}
Destory(L); //销毁链表,回收内存
}
void menu()
{
char filename[20]="info.txt";
// printf("请输入文件名:");
// scanf("%s",filename); //
int n;
while(1)
{
printf("\n-------------------------------------------------------\n");
printf("-----------------学生学情管理系统设计------------------ \n");
printf("----------------------菜单----------------------------- \n");
printf(" 1:信息录入------------| 2:显示------------------------ \n");
printf(" 3:增加记录------------| 4:修改------------------------ \n");
printf(" 5:删除----------------| 6:检索------------------------ \n");
printf(" 7:成绩统计------------| 8:智育排名------------------ \n");
printf(" 0:退出 | \n");
printf("------------------------------------------------------- \n");
printf("------------更多功能,请关注公众号:退学通知书---------- \n");
printf("------------------------------------------------------- \n");
printf(">>>>>请选择菜单中的一项:");
scanf("%d",&n);
if(n==0)
{
printf(" see you next time! \n");
printf(" 再见! \n");
break;
}
else if(n<0||n>8)
{
printf("输入错误!\n");
system("pause") ;
}
switch(n)
{
case 1:addAll(filename); //信息录入 finished
break;
case 2:dispAll(filename); //显示 finished
break;
case 3:addStudent(filename); //增加记录 finished //错误提示 名字不能有数字 分数0-100
break;
case 4:update(filename); //修改 finished //学号姓名检索
break;
case 5:delStu(filename); //删除 finished //学号姓名检索
break;
case 6:search(filename); //检索 finished //模糊查询
break;
case 7:scoresSTATIC(filename); //成绩统计 finished
break;
case 8:intelSort(filename); //智育排名 finished
break;
}
}
}
//-------------学生信息操作end---------------
int main()
{
menu();
}