#include "stdio.h" /*標準輸入輸出函數庫*/#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"/*關注公眾號:C語言與cpp編程,回復"源碼",獲取更多*/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*/ }}}