学生成绩管理系统
这是我大一的课程设计作业,供大家参考。
该程序利用Window文件和getch()函数通过“pgup”,“pgdn”键选择功能菜单,其中具体的函数功能我也不是很清楚,借鉴了一些大佬的对这部分的运用代码。
还有如图其他的功能,详细代码如下,有详细注解。
#include <iostream>//输入输出流
#include <string.h>
#include <stdlib.h>
#include <conio.h>//屏幕操作函数
#include <windows.h>//
#include <mem.h>//内存操作函数
#include <ctype.h>//字符操作函数
#include <unistd.h>
#define NR(x) (sizeof(x)/sizeof(x[0]+0))
#define TITLE " 学生成绩管理系统 "
#define AUTHOR " 作者:SuperOnly2222 "
#define DATE " 日期:2020年11月8日 "
#define SIZE 100
#define N 3
typedef int Status;
using namespace std;
typedef struct s1
{
char num[13];
char name[15];
int score[N];
int sum;//总分
float average;
int order;//名次
struct s1 *next;
}Student;
enum 定义枚举Keyboard的键值数据
{
UP = 72,
DOWN = 80 ,
LEFT = 75 ,
RIGHT = 77 ,
ENTER = 13 ,
ESC = 27 ,
};
char *menu[]={
"***************MENU*************",
"||1. 输入记录 ||",
"||2. 删除记录 ||",
"||3. 显示所有记录 ||",
"||4. 按姓名查找记录 ||",
"||5. 保存文件 ||",
"||6. 读入文件记录 ||",
"||7. 计算总分和平均分 ||",
"||8. 插入记录 ||",
"||9. 复制文件 ||",
"||10. 排序 ||",
"||11. 索引 ||",
"||12. 分类合计 ||",
"||13. 退出 ||"
};
CONSOLE_CURSOR_INFO cci;
//定义结构体
COORD pos = {0,0};
//定义默认的坐标位置
Student *Init();
//初始化
Student *Create();
//创建链表
Student *Delete(Student *h);
//删除
void Print(Student *h);
//输出
void Search(Student *h);
//查找
void Save(Student *h);
//保存文件
Student *Load();
//读文件
void Computer(Student *h);
//计算总分和平均分
Student *Insert(Student *h);
//插入
void Copy();
//拷贝文件
Student *Sort(Student *h);
//排序
Student *Index (Student *h);
//索引
void Total (Student *h);
//分类合计
int showmenu(HANDLE hOut ,char **menu , int size , int index);
//菜单界面
int get_userinput(int *index , int size);
main()
{
int i;
Student *head;
head=Init();
system("cls");//清屏
int ret ;
int index=0 ;
HANDLE hOut;
SetConsoleTitleA(TITLE);
hOut = GetStdHandle(STD_OUTPUT_HANDLE);//获取当前的句柄,设置为标准输出句柄
GetConsoleCursorInfo(hOut, &cci); //获取光标信息
cci.dwSize = 1; //设置光标大小
cci.bVisible = 0; //设置光标不可见 FALSE
SetConsoleCursorInfo(hOut, &cci);//设置(应用)光标信息
for(;;)
{
showmenu(hOut , menu , NR(menu) , index);
ret = get_userinput(&index , NR(menu));
if(ret == ESC)
break ;
if(ret == ENTER)
{
switch(index)
{
case 1:head=Create();break;
case 2:head=Delete(head);break;
case 3:Print(head);break;
case 4:Search(head);break;
case 5:Save(head);break;
case 6:head=Load();break;
case 7:Computer(head);break;
case 8:head=Insert(head);break;
case 9:Copy();break;
case 10:head=Sort(head);break;
case 11:head=Index(head);break;
case 12:Total(head);break;
case 13:exit(0);//程序结束
}
}
}
}
int showmenu(HANDLE hOut ,char **menu , int size , int index)
{
int i ;
system("cls");
SetConsoleTextAttribute(hOut, 0x9); //设置显示的文本的颜色
pos.X = 40;
pos.Y = 0 ;//初始化控制台显示的X,Y轴的坐标
SetConsoleCursorPosition(hOut,pos);///两个参数分别是指定哪个窗体,具体位置
printf("%s",TITLE);//调用printf在控制台对应的位置上输出
pos.X = 42;
pos.Y = 1 ;
SetConsoleCursorPosition(hOut,pos);
printf("%s",AUTHOR);
pos.X = 40;
pos.Y = 2 ;
SetConsoleCursorPosition(hOut,pos);
printf("%s",DATE);
for(i = 0 ; i < size ; i++)
{
if(i == index) //如果i==index表示在当前选项的位置,默认初始化显示是第一项,显示为红色,当按下上下按键选择的时候,光标会移动,也就看到了列表选择的现象
{
SetConsoleTextAttribute(hOut, FOREGROUND_BLUE ); //选择项变红色
pos.X = 40;
pos.Y = 5+i;
SetConsoleCursorPosition(hOut,pos);//设置光标坐标
printf("%s",menu[i]);
}
else//否则显示为白色
{
SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); //白色
pos.X = 40;
pos.Y = 5+i;
SetConsoleCursorPosition(hOut,pos); //设置光标坐标
printf("%s",menu[i]);
}
}
fflush(stdout);
//清空输出缓冲区,并把缓冲区内容输出:对标准输出流的清理,但是它并不是把数据丢掉,而是及时地打印数据到屏幕上。标准输出是以行为单位进行的,也即碰到\n才打印数据到屏幕。
}
//获取用户输入的接口
int get_userinput(int *index , int size)
{
int ch ;
ch = getch();//获取指令,等待你按下任意键之后,把该键字符所对应的ASCII码赋给ch,再执行下面的语句。
switch(ch)
{
case UP : if(*index > 0) *index -= 1 ; break; //如果选择上,那么光标向上移动 ,*index的值减一
case DOWN:if(*index < size -1) *index += 1 ; break;//如果选择下,那么光标向下移动 ,*index的值加一
case LEFT: return 0; //无回应
case RIGHT:return 0;
case ENTER: return ENTER ;//回车
case ESC: return ESC ;//ESC
}
return 0 ;
}
//初始化链表
Student *Init()
{
return NULL;
//初始化单链表为空
}
//输入长度校验函数
int inputs(char *prompt,char *s,int count)
{
char p[100];
do{
printf(prompt);//显示提示信息
scanf("%s",p);//输入字符串
if(strlen(p)>count)
printf("\n Too Long! \n");//长度长度校验
}while(strlen(p)>count);
strcpy(s,p);//将输入的字符串拷贝到字符串s中
}
//创建链表
Student *Create()
{
system("cls");
system("color f1");
int i;
int s;
float ave;
Student *h=NULL;
Student *stu;//指向结构体的指针
for(;;)//无限循环
{
stu=(Student*)malloc(sizeof(Student));//申请储存空间
if(!stu)//如果stu指针为空
{
printf("ERROR");//输出内存溢出
return NULL;
}
inputs("enter num:",stu->num,12);//输入学号并校验
if(stu->num[0]=='@') break;//学号首字符为@结束输入
inputs("enter name:",stu->name,15);//输入名字并校验
printf("Please input %d scores:\n",N);//输入N门课的成绩
s=0;//令学生总分初值为零
for (i=0;i<N;i++)
{
do{
printf("score%d:",i+1);//提示输入第几门课程
scanf("%d",&stu->score[i]);//输入成绩
if(stu->score[i]>100||stu->score[i]<0)
printf ("ERROR! Please repeat input!\n ");
}while (stu->score[i]>100||stu->score[i]<0);
s=s+stu->score[i];//累加求总分
}
stu->sum=s;//将总分保存
ave=s/N;
stu->average=ave;
stu->order=0;//末排序前此值为0
stu->next=h;//将头节点作为新输入结点的后继结点
h=stu;//新输入结点为新的头结点
}
return (h);//返回头指针
}
//显示记录
void Print(Student *h)
{
int i=0;//统计记录条数
Student *p;//移动指针
system("cls");//清屏
system("color f1");
p=h;
printf("\n\n\n*******************************STUDENT**********************************\n");
printf("|rec| num | name | sc1| sc2| sc3| sum |aveage |order|\n");
printf("|---|------------|---------------|----|----|----|--------|-------|-----|\n");
while (p!=NULL)
{
i++;
printf("|%3d|%-12s|%-15s|%4d|%4d|%4d| %4.2d | %4.2f | %3d |\n",i,p->num,p->name,p->score[0],p->score[1],p->score[2],p->sum,p->average,p->order);
p=p->next;
}
printf("**************************************END*******************************\n");
system("pause");
}
//删除记录
Student *Delete(Student *h)
{
Student *p,*q;//*p为查找到要删除的结点指针,*q为*p的前趋指针
char s[12];//存放学号
system("cls");
system("color f1");
printf ("Please deleted num:\n");//显示提示信息
scanf("%s",s);//输入要删除记录的学号
q=p=h;//给q和p赋初值头指针
while((strcmp(p->num,s)!=0)&&(p!=NULL))//当记录的学号不是要查找的或指针不为空时
{
q=p;//将p指针值赋给q作为p的前趋指针
p=p->next;//查找下一条记录
}
if (p==NULL)//p为空,记录中们没有该学号
printf("\nList no %s student\n",s);
else//p不为空,输出找到的记录信息
{
printf("\n\n\n******************************STUDENT*******************************\n");
printf("| num | name | sc1| sc2| sc3| sum |aveage |order|\n");
printf("|------------|---------------|----|----|----|--------|-------|-----|\n");
printf("|%-12s|%-15s|%4d|%4d|%4d| %4.2f | %4.2d | %3d |\n",p->num,p->name,p->score[0],p->score[1],p->score[2],p->sum,p->average,p->order);
printf("*******************************END**********************************\n");
getch();//按任意键后,开始删除
if(p==h)//此时被删结点是头结点
h=p->next;//修改头指针使其指向被删记录的下一条记录
else
q->next=p->next;//执行删除操作,使q的后继结点指向p的后继结点
free(p);//释放p所指结点的空间
printf("\n Have deleted num %s student\n",s);
printf("Dont't forget save!!!");//保存文件
}
return (h);//返回头指针
system("pause");
}
//查找记录
void Search(Student *h)
{
Student *p;//移动指针
char s[15];//存放名字的字符数组
system("cls");
system("color f1");
printf("Please enter name for search:\n");
scanf ("%s",s);
p=h;//将头指针赋给p
while (strcmp(p->name,s)&&p!=NULL)//当记录的名字不是要找的或指针不为空时
p=p->next;//移动指针,指向下一指针
if(p==NULL)//如果指针为空
printf ("\nList no %s student \n",s);
else
{
printf("********************************STUDENT*****************************************\n");
printf("|num | name |score1|score2|score3| sum | average |order|\n");
printf("|-------------|-------------------|------|------|------|-------|---------|-----|\n");
printf("|%-12s|%-15s|%4d|%4d|%4d| %4.2d | %4.2f | %3d |\n",p->num,p->name,p->score[0],p->score[1],p->score[2],p->sum,p->average,p->order);
printf("**************************************END***************************************\n");
}
system("pause");
}
//插入记录
Student *Insert(Student *h)
{
system("cls");
system("color f1");
Student *p,*q,*stu;//*p指向插入位置,*q是*p的前,stu是新插入记录
char s[12];//保存插入点位置的学号
int s1,i;
printf("Please enter the location before the num:\n");
scanf ("%s",s);//输入插入点学号
printf("\nPlease input new record\n");
stu=(Student*)malloc(sizeof(Student));//申请空间
if(!stu)
{
printf("\nout of memory");//如果没有申请到,则内存溢出
return NULL;//返回空指针
}
inputs("enter num:",stu->num,12);
inputs("enter name:",stu->name,15);
printf("Please input %d score \n",N);//提示输入分数
s1=0;//保存新记录的总分,初值为0
for(i=0;i<N;i++)
{
do{
printf("score%d:",i+1);//提示输入第几门课程
scanf("%d",&stu->score[i]);//输入成绩
if(stu->score[i]>100||stu->score[i]<0)
printf ("ERROR! Please repeat input\n ");
}while (stu->score[i]>100||stu->score[i]<0);
s1+=stu->score[i];//累加求总分
}
stu->sum=s1;//将总分保存
stu->average=(float)s1/N;//是平均分保留小数位
stu->order=0;//末排序前此值为0
stu->next=NULL;//将后继结点设为空
p=h;//将指针赋值给p
q=h;//将指针赋值给q
while (p->num==s&&p!=NULL)//查找插入位置
{
q=p;//保存指针p,使q作为下一个p的前趋
p=p->next;//指针p后移
}
if(p==NULL)//如果p为空,说明没有找到指定结点
{
if(p==h)//同时p==h说明链表为空
h=stu;//新记录为头指针
else
q->next=stu;//p为空,但p不等于h,将新结点插在表尾
}
else
{
if(p==h)
{
stu->next=p;//如果p==h,则新结点插入在第一个结点之前
h=stu;//新结点为新的头结点
}
else
{
stu->next=p;//p不是头结点,则在中间摸个位置,新节点的后继结点为p
q->next=stu;//新结点的前趋结点为q
}
}
printf("\n ----Have insert %s student----\n",stu->name);
printf("---Don't forget save!!!---");
return (h);
system("pause");
}
//排序
Student *Sort(Student *h)
{
system("cls");
system("color f1");
int i=0;//保存名次
Student *p,*q,*t,*h1;// 定义临时指针
h1=h->next;//将原表头指针所指的下一个结点作为头指针
h->next=NULL;//第一个结点为新表的头结点
while (h1!=NULL)
{
t=h1;//去原表的头结点
h1=h1->next;//原表头结点指针后移
p=h;//设定移动指针怕p,从头指针开始
q=h;//再设定移动指针q作为p的前驱,初值为头指针
while ((t->sum<p->sum)&&(p!=NULL))//进行总分比较
{
q=p;//待排序点值小,则新表指针后移
p=p->next;
}
if(p==q)///待排序点小,排在首位
{
t->next=p;//待排序点的后记为p
h=t;//新头结点为待排序点
}
else
//待排序点插在中间某个位置q和p之间
//p为空则是尾部
{
t->next=p;//t的后继是p
q->next=t;//
}
}
p=h;
while (p!=NULL)
{
i++;//结点序号
p->order=i;//将名次赋值
p=p->next;
}
printf("Sort success!!!\n");
Print(h);
return h;
system("pause");
}
//计算总分和平均分
void Computer(Student *h)
{
float ave;
system("color f1");
Student *p;
int i=0;//保存记录条数,初值为0
long s=0;//总分初值为0
float average=0;//平均分初值为零
p=h;//从头指针开始
while (p!=NULL)
{
s+=p->sum;
i++;
p=p->next;
}
ave=s/i;
average=ave;
printf("\n--All student sum score is :%ld average is %5.2f\n",s,average);
system("pause");
}
//索引
Student *Index(Student *h)
{
system("color f1");
Student *p,*q,*t,*h1;
h1=h->next;//将原表头指针所指的下一个结点作为头指针
h->next=NULL;//第一个结点为新表的头结点
while (h1!=NULL)
{
t=h1;//去原表的头结点
h1=h1->next;
p=h;
q=h;
while (strcmp(t->num,p->num)>0&&p!=NULL)//学号比较
{
q=p;
//待排序的值小,往后插
p=p->next;
//新表指针后移
}
if(p==q)//待排序点小,排在首位
{
t->next=p;// 待排序后继为p
h=t;//新头结点为待排序点
}
else
//待排序点插在中间某个位置q和p之间
//p为空则是尾部
{
t->next=p;
q->next=t;
}
}
printf("Index success!!!\n");
Print(h);
return h;
system("pause");
}
//分类合计
void Total(Student *h)
{
system("color f1");
Student *p,*q;//临时变量
char snum[11],qnum[11],*ptr;//保存班级号
float s1,ave;
int i;//班级人数
system("cls");
printf("\n\n***************Tatal************\n");
printf("---class---------sum------------average----\n");
p=h;
while (p!=NULL)
{
memcpy(snum,p->num,10);//从学号中拷贝10个字节到班级号中
snum[10]='\0';//字符串结束标志
q=p->next;//指针指向待比较的记录
s1=p->sum;//当前班级的总分初值为该班级第一条记录的总分
ave=p->average;//当前班级的平均分初值为该班级第一条记录的平均分
i=1;
while (q!=NULL)//内循环
{
memcpy(qnum,q->num,10);//从学号中拷贝10个字节到班级号中
qnum[10]='\0';//字符串结束符号
if(snum[9]==qnum[9])//比较班级号
{
s1+=q->sum;//累加总分
ave+=q->average;
i++;//累加班级人数
q=q->next;//下一条记录
}
else
break;//不是一个班级的结束本次内循环
}
printf("%s %12.2f %5.2f\n",snum,s1,ave/i);
if(q==NULL){
break;//如果 当前指针为空,外循环结束,程序结束
}
else{
p=q;//当前记录作为新班级的第一条记录开始新的比较
}
}
printf("----------------------------------------------");
system("pause");
}
//保存数据到文件
void Save(Student *h)
{
system("color f1");
FILE *fp;
Student *p;
fp=fopen("c:\\f1\\student1.txt","wb");
if(fp==NULL)//为输出打开一个二进制文件,如果没有则建立
{
printf ("Can't open file\n");
system("pause");
return ;
}
printf("\nSaving file......\n");
p=h;//移动指针从头指针开始
while (p!=NULL)
{
fwrite(p,sizeof(Student),1,fp);//写入一条数据
p=p->next;//指针后移
}
fclose(fp);//关闭文件
printf("------Save Success!!!------\n");
system("pause");
}
//从文件中读数据
Student *Load()
{
system("color f1");
Student *p,*q,*h=NULL;
FILE *fp;//定义指向文件的指针
fp=fopen("c:\\f1\\student1.txt","rb");
if(fp==NULL)//打开一个二进制文件,为读方式
{
printf("Can't open file\n");
system("pause");
}
else
{
printf("\n ------Loading file!!!-------\n");
p=(Student*)malloc(sizeof(Student));//申请空间
if(!p)
{
printf("Out of memory!\n");
return h;//返回空头指针
}
h=p;//如果申请到空间,将其作为头指针
while(!feof(fp))//循环读数据,直到文件尾结束
{
if(fread(p,sizeof(Student),1,fp)!=1)
printf("File write error\n");
break;//如果没有读到数据 ,则跳出循环
p->next=(Student*)malloc(sizeof(Student));//为下一个结点申请空间
if(!p->next)
{
printf("Out of memory!\n");
return h;
}
q=p;//保存当前指针,作为下一结点前驱
p=p->next;//指针后移,新读入的数据连到当前表尾
}
q->next=NULL;//最后一个结点的后继指针为空
fclose(fp);
printf("---You have read data from file successfully!!!---\n");
system("pause");
}
return h;
system("pause");
}
//文件拷贝
void Copy()
{
system("color f1");
char outfile[10],infile[10];
FILE *sfp,*tfp;//源文件指针和目标文件指针
Student *p=NULL;
system("cls");
sfp=fopen("c:\\f1\\student1.txt","rb");//二进制读方式打开源文件
if(sfp==NULL)
{
printf("Can't open file\n");
return ;
}
tfp=fopen("c:\\f1\\student2.txt","wb");
if(tfp==NULL)
{
printf("Can't open file\n");
return ;
}
while (!feof(sfp))//读文件到文件尾
{
if(1!=fread(p,sizeof(Student),1,sfp))
break;//块读
fwrite(p,sizeof(Student),1,tfp);//快写
}
fclose(sfp);
fclose(tfp);
printf("You have copy file successfully!!!\n");
system("pause");
}