#include "stdlib.h" /*標準函數庫*/
#include "string.h" /*字符串函數庫*/
#include "conio.h" /*屏幕操作函數庫*/
#define HEADER1 " ----------------------------STUDENT---------------------------------- \n"
#define HEADER2 " | number | name |Comp|Math|Eng | sum | ave |mici | \n"
#define HEADER3 " |---------------|---------------|----|----|----|--------|-------|-----| "
#define FORMAT " | %-10s |%-15s|%4d|%4d|%4d| %4d | %.2f |%4d |\n"
#define DATA p->data.num,p->data.name,p->data.egrade,p->data.mgrade,p->data.cgrade,p->data.total,p->data.ave,p->data.mingci
#define END " --------------------------------------------------------------------- \n"
int saveflag=0; /*是否需要存盤的標誌變量*/
/*定義與學生有關的數據結構*/
typedef struct student /*標記為student*/
{
char num[10]; /*學號*/
char name[15]; /*姓名*/
int cgrade; /*C語言成績*/
int mgrade; /*數學成績*/
int egrade; /*英語成績*/
int total; /*總分*/
float ave; /*平均分*/
int mingci; /*名次*/
};
/*定義每條記錄或結點的數據結構,標記為:node*/
typedef struct node
{
struct student data; /*數據域*/
struct node *next; /*指針域*/
}Node,*Link; /*Node為node類型的結構變量,*Link為node類型的指針變量*/
void menu() /*主菜單*/
{
system("cls"); /*調用DOS命令,清屏.與clrscr()功能相同*/
textcolor(10); /*在文本模式中選擇新的字符顏色*/
gotoxy(10,5); /*在文本窗口中設置光標*/
cprintf(" The Students' Grade Management System \n");
gotoxy(10,8);
cprintf(" *************************Menu********************************\n");
gotoxy(10,9);
cprintf(" * 1 input record 2 delete record *\n");
gotoxy(10,10);
cprintf(" * 3 search record 4 modify record *\n");
gotoxy(10,11);
cprintf(" * 5 insert record 6 count record *\n");
gotoxy(10,12);
cprintf(" * 7 sort reord 8 save record *\n");
gotoxy(10,13);
cprintf(" * 9 display record 0 quit system *\n");
gotoxy(10,14);
cprintf(" *************************************************************\n");
/*cprintf()送格式化輸出至文本窗口屏幕中*/
}
void printheader() /*格式化輸出表頭*/
{
printf(HEADER1);
printf(HEADER2);
printf(HEADER3);
}
void printdata(Node *pp) /*格式化輸出表中數據*/
{
Node* p;
p=pp;
printf(FORMAT,DATA);
}
void Wrong() /*輸出按鍵錯誤信息*/
{
printf("\n\n\n\n\n***********Error:input has wrong! press any key to continue**********\n");
getchar();
}
void Nofind() /*輸出未查找此學生的信息*/
{
printf("\n=====>Not find this student!\n");
}
void Disp(Link l) /*顯示單鏈表l中存儲的學生記錄,內容為student結構中定義的內容*/
{
Node *p;
p=l->next; /*l存儲的是單鏈表中頭結點的指針,該頭結點沒有存儲學生信息,指針域指向的後繼結點才有學生信息*/
if(!p) /*p==NULL,NUll在stdlib中定義為0*/
{
printf("\n=====>Not student record!\n");
getchar();
return;
}
printf("\n\n");
printheader(); /*輸出表格頭部*/
while(p) /*逐條輸出鏈表中存儲的學生信息*/
{
printdata(p);
p=p->next; /*移動直下壹個結點*/
printf(HEADER3);
}
getchar();
}
/*************************************************************
作用:用於定位鏈表中符合要求的節點,並返回指向該節點的指針
參數:findmess[]保存要查找的具體內容; nameornum[]保存按什麽查找;
在單鏈表l中查找;
**************************************************************/
Node* Locate(Link l,char findmess[],char nameornum[])
{
Node *r;
if(strcmp(nameornum,"num")==0) /*按學號查詢*/
{
r=l->next;
while(r)
{
if(strcmp(r->data.num,findmess)==0) /*若找到findmess值的學號*/
return r;
r=r->next;
}
}
else if(strcmp(nameornum,"name")==0) /*按姓名查詢*/
{
r=l->next;
while(r)
{
if(strcmp(r->data.name,findmess)==0) /*若找到findmess值的學生姓名*/
return r;
r=r->next;
}
}
return 0; /*若未找到,返回壹個空指針*/
}
/*輸入字符串,並進行長度驗證(長度<lens)*/
void stringinput(char *t,int lens,char *notice)
{
char n[255];
do{
printf(notice); /*顯示提示信息*/
scanf("%s",n); /*輸入字符串*/
if(strlen(n)>lens)printf("\n exceed the required length! \n"); /*進行長度校驗,超過lens值重新輸入*/
}while(strlen(n)>lens);
strcpy(t,n); /*將輸入的字符串拷貝到字符串t中*/
}
/*輸入分數,0<=分數<=100)*/
int numberinput(char *notice)
{
int t=0;
do{
printf(notice); /*顯示提示信息*/
scanf("%d",&t); /*輸入分數*/
if(t>100 || t<0) printf("\n score must in [0,100]! \n"); /*進行分數校驗*/
}while(t>100 || t<0);
return t;
}
/*增加學生記錄*/
void Add(Link l)
{
Node *p,*r,*s; /*實現添加操作的臨時的結構體指針變量*/
char ch,flag=0,num[10];
r=l;
s=l->next;
system("cls");
Disp(l); /*先打印出已有的學生信息*/
while(r->next!=NULL)
r=r->next; /*將指針移至於鏈表最末尾,準備添加記錄*/
while(1) /*壹次可輸入多條記錄,直至輸入學號為0的記錄結點添加操作*/
{
while(1) /*輸入學號,保證該學號沒有被使用,若輸入學號為0,則退出添加記錄操作*/
{
stringinput(num,10,"input number(press '0'return menu):"); /*格式化輸入學號並檢驗*/
flag=0;
if(strcmp(num,"0")==0) /*輸入為0,則退出添加操作,返回主界面*/
{return;}
s=l->next;
while(s) /*查詢該學號是否已經存在,若存在則要求重新輸入壹個未被占用的學號*/
{
if(strcmp(s->data.num,num)==0)
{
flag=1;
break;
}
s=s->next;
}
if(flag==1) /*提示用戶是否重新輸入*/
{ getchar();
printf("=====>The number %s is not existing,try again?(y/n):",num);
scanf("%c",&ch);
if(ch=='y'||ch=='Y')
continue;
else
return;
}
else
{break;}
}
p=(Node *)malloc(sizeof(Node)); /*申請內存空間*/
if(!p)
{
printf("\n allocate memory failure "); /*如沒有申請到,打印提示信息*/
return ; /*返回主界面*/
}
strcpy(p->data.num,num); /*將字符串num拷貝到p->data.num中*/
stringinput(p->data.name,15,"Name:");
p->data.cgrade=numberinput("C language Score[0-100]:"); /*輸入並檢驗分數,分數必須在0-100之間*/
p->data.mgrade=numberinput("Math Score[0-100]:"); /*輸入並檢驗分數,分數必須在0-100之間*/
p->data.egrade=numberinput("English Score[0-100]:"); /*輸入並檢驗分數,分數必須在0-100之間*/
p->data.total=p->data.egrade+p->data.cgrade+p->data.mgrade; /*計算總分*/
p->data.ave=(float)(p->data.total/3); /*計算平均分*/
p->data.mingci=0;
p->next=NULL; /*表明這是鏈表的尾部結點*/
r->next=p; /*將新建的結點加入鏈表尾部中*/
r=p;
saveflag=1;
}
return ;
}
void Qur(Link l) /*按學號或姓名,查詢學生記錄*/
{
int select; /*1:按學號查,2:按姓名查,其他:返回主界面(菜單)*/
char searchinput[20]; /*保存用戶輸入的查詢內容*/
Node *p;
if(!l->next) /*若鏈表為空*/
{
system("cls");
printf("\n=====>No student record!\n");
getchar();
return;
}
system("cls");
printf("\n =====>1 Search by number =====>2 Search by name\n");
printf(" please choice[1,2]:");
scanf("%d",&select);
if(select==1) /*按學號查詢*/
{
stringinput(searchinput,10,"input the existing student number:");
p=Locate(l,searchinput,"num");/*在l中查找學號為searchinput值的節點,並返回節點的指針*/
if(p) /*若p!=NULL*/
{
printheader();
printdata(p);
printf(END);
printf("press any key to return");
getchar();
}
else
Nofind();
getchar();
}
else if(select==2) /*按姓名查詢*/
{
stringinput(searchinput,15,"input the existing student name:");
p=Locate(l,searchinput,"name");
if(p)
{
printheader();
printdata(p);
printf(END);
printf("press any key to return");
getchar();
}
else
Nofind();
getchar();
}
else
Wrong();
getchar();
}
/*刪除學生記錄:先找到保存該學生記錄的節點,然後刪除該節點*/
void Del(Link l)
{
int sel;
Node *p,*r;
char findmess[20];
if(!l->next)
{ system("cls");
printf("\n=====>No student record!\n");
getchar();
return;
}
system("cls");
Disp(l);
printf("\n =====>1 Delete by number =====>2 Delete by name\n");
printf(" please choice[1,2]:");
scanf("%d",&sel);
if(sel==1)
{
stringinput(findmess,10,"input the existing student number:");
p=Locate(l,findmess,"num");
if(p) /*p!=NULL*/
{
r=l;
while(r->next!=p)
r=r->next;
r->next=p->next;/*將p所指節點從鏈表中去除*/
free(p); /*釋放內存空間*/
printf("\n=====>delete success!\n");
getchar();
saveflag=1;
}
else
Nofind();
getchar();
}
else if(sel==2) /*先按姓名查詢到該記錄所在的節點*/
{
stringinput(findmess,15,"input the existing student name");
p=Locate(l,findmess,"name");
if(p)
{
r=l;
while(r->next!=p)
r=r->next;
r->next=p->next;
free(p);
printf("\n=====>delete success!\n");
getchar();
saveflag=1;
}
else
Nofind();
getchar();
}
else
Wrong();
getchar();
}
/*修改學生記錄。先按輸入的學號查詢到該記錄,然後提示用戶修改學號之外的值,學號不能修改*/
void Modify(Link l)
{
Node *p;
char findmess[20];
if(!l->next)
{ system("cls");
printf("\n=====>No student record!\n");
getchar();
return;
}
system("cls");
printf("modify student recorder");
Disp(l);
stringinput(findmess,10,"input the existing student number:"); /*輸入並檢驗該學號*/
p=Locate(l,findmess,"num"); /*查詢到該節點*/
if(p) /*若p!=NULL,表明已經找到該節點*/
{
printf("Number:%s,\n",p->data.num);
printf("Name:%s,",p->data.name);
stringinput(p->data.name,15,"input new name:");
printf("C language score:%d,",p->data.cgrade);
p->data.cgrade=numberinput("C language Score[0-100]:");
printf("Math score:%d,",p->data.mgrade);
p->data.mgrade=numberinput("Math Score[0-100]:");
printf("English score:%d,",p->data.egrade);
p->data.egrade=numberinput("English Score[0-100]:");
p->data.total=p->data.egrade+p->data.cgrade+p->data.mgrade;
p->data.ave=(float)(p->data.total/3);
p->data.mingci=0;
printf("\n=====>modify success!\n");
Disp(l);
saveflag=1;
}
else
Nofind();
getchar();
}
/*插入記錄:按學號查詢到要插入的節點的位置,然後在該學號之後插入壹個新節點。*/
void Insert(Link l)
{
Link p,v,newinfo; /*p指向插入位置,newinfo指新插入記錄*/
char ch,num[10],s[10]; /*s[]保存插入點位置之前的學號,num[]保存輸入的新記錄的學號*/
int flag=0;
v=l->next;
system("cls");
Disp(l);
while(1)
{ stringinput(s,10,"please input insert location after the Number:");
flag=0;v=l->next;
while(v) /*查詢該學號是否存在,flag=1表示該學號存在*/
{
if(strcmp(v->data.num,s)==0) {flag=1;break;}
v=v->next;
}
if(flag==1)
break; /*若學號存在,則進行插入之前的新記錄的輸入操作*/
else
{ getchar();
printf("\n=====>The number %s is not existing,try again?(y/n):",s);
scanf("%c",&ch);
if(ch=='y'||ch=='Y')
{continue;}
else
{return;}
}
}
/*以下新記錄的輸入操作與Add()相同*/
stringinput(num,10,"input new student Number:");
v=l->next;
while(v)
{
if(strcmp(v->data.num,num)==0)
{
printf("=====>Sorry,the new number:'%s' is existing !\n",num);
printheader();
printdata(v);
printf("\n");
getchar();
return;
}
v=v->next;
}
newinfo=(Node *)malloc(sizeof(Node));
if(!newinfo)
{
printf("\n allocate memory failure "); /*如沒有申請到,打印提示信息*/
return ; /*返回主界面*/
}
strcpy(newinfo->data.num,num);
stringinput(newinfo->data.name,15,"Name:");
newinfo->data.cgrade=numberinput("C language Score[0-100]:");
newinfo->data.mgrade=numberinput("Math Score[0-100]:");
newinfo->data.egrade=numberinput("English Score[0-100]:");
newinfo->data.total=newinfo->data.egrade+newinfo->data.cgrade+newinfo->data.mgrade;
newinfo->data.ave=(float)(newinfo->data.total/3);
newinfo->data.mingci=0;
newinfo->next=NULL;
saveflag=1; /*在main()有對該全局變量的判斷,若為1,則進行存盤操作*/
/*將指針賦值給p,因為l中的頭節點的下壹個節點才實際保存著學生的記錄*/
p=l->next;
while(1)
{
if(strcmp(p->data.num,s)==0) /*在鏈表中插入壹個節點*/
{
newinfo->next=p->next;
p->next=newinfo;
break;
}
p=p->next;
}
Disp(l);
printf("\n\n");
getchar();
}
/*統計該班的總分第壹名和單科第壹,和各科不及格人數*/
void Tongji(Link l)
{
Node *pm,*pe,*pc,*pt; /*用於指向分數最高的節點*/
Node *r=l->next;
int countc=0,countm=0,counte=0; /*保存三門成績中不及格的人數*/
if(!r)
{ system("cls");
printf("\n=====>Not student record!\n");
getchar();
return ;
}
system("cls");
Disp(l);
pm=pe=pc=pt=r;
while(r)
{
if(r->data.cgrade<60) countc++;
if(r->data.mgrade<60) countm++;
if(r->data.egrade<60) counte++;
if(r->data.cgrade>=pc->data.cgrade) pc=r;
if(r->data.mgrade>=pm->data.mgrade) pm=r;
if(r->data.egrade>=pe->data.egrade) pe=r;
if(r->data.total>=pt->data.total) pt=r;
r=r->next;
}
printf("\n------------------------------the TongJi result--------------------------------\n");
printf("C Language<60:%d (ren)\n",countc);
printf("Math <60:%d (ren)\n",countm);
printf("English <60:%d (ren)\n",counte);
printf("-------------------------------------------------------------------------------\n");
printf("The highest student by total scroe name:%s totoal score:%d\n",pt->data.name,pt->data.total);
printf("The highest student by English score name:%s totoal score:%d\n",pe->data.name,pe->data.egrade);
printf("The highest student by Math score name:%s totoal score:%d\n",pm->data.name,pm->data.mgrade);
printf("The highest student by C score name:%s totoal score:%d\n",pc->data.name,pc->data.cgrade);
printf("\n\npress any key to return");
getchar();
}
/*利用插入排序法實現單鏈表的按總分字段的降序排序,從高到低*/
void Sort(Link l)
{
Link ll;
Node *p,*rr,*s;
int i=0;
if(l->next==NULL)
{ system("cls");
printf("\n=====>Not student record!\n");
getchar();
return ;
}
ll=(Node*)malloc(sizeof(Node)); /*用於創建新的節點*/
if(!ll)
{
printf("\n allocate memory failure "); /*如沒有申請到,打印提示信息*/
return ; /*返回主界面*/
}
ll->next=NULL;
system("cls");
Disp(l); /*顯示排序前的所有學生記錄*/
p=l->next;
while(p) /*p!=NULL*/
{
s=(Node*)malloc(sizeof(Node)); /*新建節點用於保存從原鏈表中取出的節點信息*/
if(!s) /*s==NULL*/
{
printf("\n allocate memory failure "); /*如沒有申請到,打印提示信息*/
return ; /*返回主界面*/
}
s->data=p->data; /*填數據域*/
s->next=NULL; /*指針域為空*/
rr=ll;
/*rr鏈表於存儲插入單個節點後保持排序的鏈表,ll是這個鏈表的頭指針,每次從頭開始查找插入位置*/
while(rr->next!=NULL && rr->next->data.total>=p->data.total)
{rr=rr->next;} /*指針移至總分比p所指的節點的總分小的節點位置*/
if(rr->next==NULL)/*若新鏈表ll中的所有節點的總分值都比p->data.total大時,就將p所指節點加入鏈表尾部*/
rr->next=s;
else /*否則將該節點插入至第壹個總分字段比它小的節點的前面*/
{
s->next=rr->next;
rr->next=s;
}
p=p->next; /*原鏈表中的指針下移壹個節點*/
}
l->next=ll->next; /*ll中存儲是的已排序的鏈表的頭指針*/
p=l->next; /*已排好序的頭指針賦給p,準備填寫名次*/
while(p!=NULL) /*當p不為空時,進行下列操作*/
{
i++; /*結點序號*/
p->data.mingci=i; /*將名次賦值*/
p=p->next; /*指針後移*/
}
Disp(l);
saveflag=1;
printf("\n =====>sort complete!\n");
}
/*數據存盤,若用戶沒有專門進行此操作且對數據有修改,在退出系統時, 會提示用戶存盤*/
void Save(Link l)
{
FILE* fp;
Node *p;
int count=0;
fp=fopen("c:\\student","wb");/*以只寫方式打開二進制文件*/
if(fp==NULL) /*打開文件失敗*/
{
printf("\n=====>open file error!\n");
getchar();
return ;
}
p=l->next;
while(p)
{
if(fwrite(p,sizeof(Node),1,fp)==1)/*每次寫壹條記錄或壹個節點信息至文件*/
{
p=p->next;
count++;
}
else
{
break;
}
}
if(count>0)
{
getchar();
printf("\n\n\n\n\n=====>save file complete,total saved's record number is:%d\n",count);
getchar();
saveflag=0;
}
else
{system("cls");
printf("the current link is empty,no student record is saved!\n");
getchar();
}
fclose(fp); /*關閉此文件*/
}
void main()
{
Link l; /*定義鏈表*/
FILE *fp; /*文件指針*/
int select; /*保存選擇結果變量*/
char ch; /*保存(y,Y,n,N)*/
int count=0; /*保存文件中的記錄條數(或結點個數)*/
Node *p,*r; /*定義記錄指針變量*/
l=(Node*)malloc(sizeof(Node));
if(!l)
{
printf("\n allocate memory failure "); /*如沒有申請到,打印提示信息*/
return ; /*返回主界面*/
}
l->next=NULL;
r=l;
fp=fopen("C:\\student","ab+"); /*以追加方式打開壹個二進制文件,可讀可寫,若此文件不存在,會創建此文件*/
if(fp==NULL)
{
printf("\n=====>can not open file!\n");
exit(0);
}
while(!feof(fp))
{
p=(Node*)malloc(sizeof(Node));
if(!p)
{
printf(" memory malloc failure!\n"); /*沒有申請成功*/
exit(0); /*退出*/
}
if(fread(p,sizeof(Node),1,fp)==1) /*壹次從文件中讀取壹條學生成績記錄*/
{
p->next=NULL;
r->next=p;
r=p; /*r指針向後移壹個位置*/
count++;
}
}
fclose(fp); /*關閉文件*/
printf("\n=====>open file sucess,the total records number is : %d.\n",count);
menu();
while(1)
{
system("cls");
menu();
p=r;
printf("\n Please Enter your choice(0~9):"); /*顯示提示信息*/
scanf("%d",&select);
if(select==0)
{
if(saveflag==1) /*若對鏈表的數據有修改且未進行存盤操作,則此標誌為1*/
{ getchar();
printf("\n=====>Whether save the modified record to file?(y/n):");
scanf("%c",&ch);
if(ch=='y'||ch=='Y')
Save(l);
}
printf("=====>thank you for useness!");
getchar();
break;
}
switch(select)
{
case 1:Add(l);break; /*增加學生記錄*/
case 2:Del(l);break; /*刪除學生記錄*/
case 3:Qur(l);break; /*查詢學生記錄*/
case 4:Modify(l);break; /*修改學生記錄*/
case 5:Insert(l);break; /*插入學生記錄*/
case 6:Tongji(l);break; /*統計學生記錄*/
case 7:Sort(l);break; /*排序學生記錄*/
case 8:Save(l);break; /*保存學生記錄*/
case 9:system("cls");Disp(l);break; /*顯示學生記錄*/
default: Wrong();getchar();break; /*按鍵有誤,必須為數值0-9*/
}
}
}