史上最詳細c語言學生管理系統(完整的原始碼)
阿新 • • 發佈:2019-01-06
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> struct student { char sno[12]; char name[9]; char sex[5]; struct score { double China; double shuxue; double English; double sum; double average; } fenshu; int age; struct student *next; }; typedef struct student ID;//宣告結構體同義詞,方便使用 int total;//學生管理系統的實際人數 //各函式的宣告 ID* Create(); //建立學生管理系統 void Save(ID *head); //儲存學生資訊檔案 ID * Read(); //讀取學生資訊檔案 void Display(ID * head); //顯示學生資訊檔案 ID* Add(ID* head); //新增學生資訊 ID* Change(ID* head); //修改學生資訊 void Search(ID *head); //按照姓名或者型別查詢學生 ID* Delete(ID *head); //刪除學生資訊 void Sort(ID *head); /************************************************ *函式名: main(主函式) *功能:顯示主選單 *返回值:NULL *************************************************/ void main() { ID*head=NULL;//連結串列頭結點 int choice;//使用者選單選擇 while(1) { system("cls");//清屏 printf("\n"); printf("*************簡易學生管理系統*************\n\n"); printf("\t1.建立簡易學生管理系統\n\n"); printf("\t2.顯示學生檔案資訊\n\n"); printf("\t3.新增新學生\n\n"); printf("\t4.修改學生的資訊\n\n"); printf("\t5.查詢學生\n\n"); printf("\t6.刪除學生\n\n"); printf("\t7.排序學生\n\n"); printf("\t8.退出簡易學生管理系統\n\n"); printf("\n\n"); printf("請輸入你的選擇(1~8):"); scanf("%d",&choice);//選擇功能 getchar();//吸收回車符 switch(choice) { case 1: head=Create(); //建立學生管理系統子函式 break; case 2: head=Read(); //讀取學生管理系統檔案子函式 if(head!=NULL) Display(head); //顯示學生管理系統 break; case 3: head=Read(); //讀取學生管理系統檔案子函式 if(head!=NULL) head=Add(head); //新增新生 break; case 4: head=Read(); if(head!=NULL) head=Change(head); //修改新生 break; case 5: head=Read(); if(head!=NULL) Search(head); //查詢學生 break; case 6: head=Read(); if(head!=NULL) head=Delete(head); //刪除學生 break; case 7: head=Read(); if(head!=NULL) Sort(head); //排序學生 break; case 8: exit(0); //退出 break; default: printf("\n你輸入錯了,請你重新輸入\n"); getch(); } } } /*********************************************** *函式名:Create(建立) *功能:建立一個單鏈表,把資料放在連結串列裡面,一旦需要儲存,就呼叫save函式儲存在檔案中 *返回值:ID *(結構體連結串列頭節點指標) ***********************************************/ ID* Create() { int k=0; FILE *fp; //定義一個檔案指標,接收fopen的返回值,用於最後的關閉檔案 ID *head,*p1,*tail,*p3; if ((fp=fopen("student.txt","r"))==NULL) //如果檔案不存在就建立 { head=p1=tail=NULL; while(1) //這個迴圈可以實現多次新增新學生資訊 { bb1: p1= (ID*)malloc(sizeof(ID)); //給p1分配一個動態儲存空間 p1->next=NULL; printf("請輸入姓名(當你不想錄入時,在姓名處輸入*,結束錄入):\n"); fflush(stdin); scanf("%8s",p1->name); //輸入姓名 p1->name[8]=0; if(strcmp(p1->name,"*")==0) //判斷輸入的是否為*號,是則結束函式 { if(total==0) //當記錄人數為0時不建立學生檔案 { printf("你輸入了0條記錄,單鏈表沒有建立...\n"); free(p1); //釋放p1空間 return (head); //把head返回 } else { break; //跳出while迴圈 } } fflush(stdin); printf("請輸入學號: \n"); scanf("%11s",p1->sno); p3=head; //讓p3從頭開始遍歷 while(p3!=NULL) //當p3不為空時 { if((strcmp(p1->name,p3->name)==0)&&(strcmp(p1->sno,p3->sno)==0)) { free(p1); printf("你重複輸入了。\n"); goto bb1; } p3=p3->next; } //使得每個欄位都能有效結束 p1->sno[11]=0; fflush(stdin); printf("請輸入學生性別:"); scanf("%4s",p1->sex); fflush(stdin); printf("請輸入學生年齡:"); scanf("%d",&p1->age); fflush(stdin); printf("請輸入學生科目成績(語文,數學,英語):"); scanf("%lf%lf%lf",&p1->fenshu.China,&p1->fenshu.shuxue,&p1->fenshu.English); p1->fenshu.sum=p1->fenshu.China+p1->fenshu.shuxue+p1->fenshu.English; p1->fenshu.average=p1->fenshu.sum/3.0; if(head==NULL) { head=p1; //head和p2都為p1 tail=p1; } else { tail->next=p1; //第二次以後的執行命令,目的就是p1向後移,而head的位置不變 tail=p1; } total++; //錄入一個人後,總數就加1 } tail->next=NULL; //尾指標域賦值為NULL free(p1); printf("\n新建簡易學生管理系統成功,共有%d個學生\n ",total); getchar(); //這個getchar是吸收回車鍵的 Save(head); //將新建立的學生連結串列儲存到學生檔案中 } else { printf("\n\t學生資訊檔案已經存在,不能重複建立!\n\n按任意鍵返回主選單\n\n"); getch(); //輸入任意鍵進入下一步 } return head; //返回頭指標 } /*void Save(ID *head) { }*/ /************************************************ *函式名:Save(儲存) *功能:將連結串列(資料)儲存在檔案 *返回值:NULL *引數:連結串列頭節點 *************************************************/ void Save(ID *head) { FILE *fp; //定義一個檔案指標,接收fopen的返回值,用於最後的關閉檔案 ID* t ; //定義一個指標,從頭到尾遍歷一遍單鏈表,向檔案中寫入 if ((fp=fopen("student.txt","w"))==NULL) //開啟檔案來寫入 { printf("開啟檔案失敗!\n"); getch(); //輸入任意鍵進入下一步 exit(0); //退出 } t=head; //把頭指標賦給t,讓它從頭開始 while(t!=NULL) //只要t指標不為空,即等於連結串列沒有結束 { fwrite(t,sizeof(ID),1,fp); //把連結串列寫入檔案中 t=t->next; //指標後移 } fclose(fp); //把檔案關閉 printf("\n檔案儲存成功\n"); printf("\n請按任意鍵返回主選單\n"); getch(); } /************************************************ *函式名:Read(讀取學生檔案) *功能:讀取檔案中的資訊並將其放入單鏈表中,並且最後返回一個頭指標 *返回值:ID *(結構體指標) *************************************************/ ID * Read() { FILE *fp; //定義一個檔案指標,接收fopen的返回值,用於最後的關閉檔案 ID *t1,*t2,*head=NULL; if((fp=fopen("student.txt","r"))==NULL) //判斷檔案是否存在 { printf("開啟檔案失敗!沒有該檔案\n\n"); printf("請按任意鍵返回主選單\n"); getch(); return 0; } rewind(fp); //這個函式是把一個檔案的位置指標從新移至開頭,不然的話會出現一個組資料丟失 t1=(ID *) malloc(sizeof(ID)); //申請動態空間 head=t2=t1; //把t1賦給頭結點 while(!feof(fp)) //feof函式的功能是判斷這個檔案是不是結束了,如果結束了,返回一個非零值,否則返回一個0, { if(fread(t1,sizeof(ID),1,fp)!=1) //fread函式返回讀出資料項的個數 break; //如果沒有讀取內容,則結束 t1->next=(ID *)malloc(sizeof(ID)); //把在申請動態空間的同時,把t1的next指向下一個結點 t2=t1; //t2是真正的尾節點 t1=t1->next; //t1向後移一個結點 } t2->next=NULL; fclose(fp); //關閉檔案 return head; //返回一個頭指標,因為在沒有建立一個單鏈表和檔案的時候,就是靠這個頭指標進行一系列的操作的 } /************************************************ *函式名: Display(顯示學生檔案) *功能:顯示聯絡人資訊 *返回值:無返回值) *************************************************/ void Display(ID * head) { ID *t1=head; printf("\n學生姓名==學號=====性別===年齡==語文成績==數學成績==英語成績==總分==平均分\n\n"); while(t1!=NULL) { printf("%-8s%-11s %-4s %-4d %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f \n",t1->name,t1->sno,t1->sex,t1->age,t1->fenshu.China,t1->fenshu.shuxue,t1->fenshu.English,t1->fenshu.sum,t1->fenshu.average); t1=t1->next; } printf("\n\n簡易學生管理系統成功顯示\n"); printf("\n請按任意鍵返回主選單\n"); getch(); } /************************************************ *函式名: Add(新增) *功能:新增人物資訊 *返回值:ID *(結構體指標) *************************************************/ ID* Add(ID* head) { char saveflag; //存檔標誌 int k=0; ID *p1,*p2,*pa; //pa是用來放新增的資訊的,p1,p2是用來臨時移動的 p1=p2=head; //先讓它們都等於頭指標 system("cls"); //清屏 while(p1->next!=NULL) //把p1移到尾節點 p1=p1->next; bb2:pa=(ID*)malloc(sizeof(ID)); //申請動態儲存空間 printf("請輸入新增人的姓名:\n"); fflush(stdin); scanf("%8s",pa->name); fflush(stdin); printf("請輸入學號: \n"); scanf("%11s",pa->sno); p2=head; //讓p2從頭開始遍歷 while(p2!=NULL) //當p2不為空時 { if((strcmp(pa->name,p2->name)==0)&&(strcmp(pa->sno,p2->sno)==0)) { free(pa); printf("你重複輸入了!\n"); goto bb2; } p2=p2->next; } pa->name[8]=0; //使得每個欄位都能有效結束 pa->sno[11]=0; fflush(stdin); printf("請輸入學生性別:"); scanf("%4s",pa->sex); pa->sex[4]=0; fflush(stdin); printf("請輸入學生年齡:"); scanf("%d",&pa->age); fflush(stdin); printf("請輸入學生科目成績(語文,數學,英語):"); scanf("%lf%lf%lf",&pa->fenshu.China,&pa->fenshu.shuxue,&pa->fenshu.English); pa->fenshu.sum=pa->fenshu.China+pa->fenshu.shuxue+pa->fenshu.English; pa->fenshu.average=pa->fenshu.sum/3.0; p1->next=pa; //尾節點p1的next新增pa pa->next=NULL; printf("新新增學生資訊成功,是否存檔?(Y/N)\n"); fflush(stdin); scanf("%c",&saveflag);//存檔?Y or N if(saveflag=='y'||saveflag=='Y')//當輸入y Y的時候 Save(head); //呼叫儲存函式 else { printf("請按任意鍵返回主選單\n"); getch(); } free(pa); return(head); } /************************************************ *函式名: Change(修改) *功能:修改人物資訊 *返回值:ID *(結構體指標) *************************************************/ ID* Change(ID* head) { ID *p1,*p2; char saveflag; char n[10],t[12]; //存放待修改人的姓名和學號 int flag=0; //修改標誌 system("cls"); //清屏 p1=head; printf("請輸入要修改的學號:\n"); scanf("%11s",t); while(p1!=NULL) //這個while語句的作用是在遍歷整個單鏈表 { if(strcmp(p1->sno,t)==0)//判斷是不是你輸入的學號是不是和簡易學生管理系統中的相同 { flag=1; //當存在一樣的名字時, printf("\n你要修改的學生資訊為:\n"); printf("\n學生姓名==學號=====性別===年齡==語文成績==數學成績==英語成績==總分==平均分\n\n"); printf("%-8s%-11s %-4s %-4d %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f \n",p1->name,p1->sno,p1->sex,p1->age,p1->fenshu.China,p1->fenshu.shuxue,p1->fenshu.English,p1->fenshu.sum,p1->fenshu.average); bb3:printf("\n請輸入修改後的姓名:\n"); fflush(stdin); scanf("%8s",n); p2=head; //讓p2從頭開始遍歷 while(p2!=NULL)//當p2不為空時 { if((strcmp(n,p2->name)==0)&&(strcmp(t,p2->sno)==0)) { printf("你重複輸入了。\n"); goto bb3; } p2=p2->next; } strcpy(p1->name,n); p1->name[8]=0; fflush(stdin); printf("請輸入學生性別:"); scanf("%4s",p1->sex); p1->sex[4]=0; fflush(stdin); printf("請輸入學生年齡:"); scanf("%d",&p1->age); fflush(stdin); printf("請輸入學生科目成績(語文,數學,英語):"); scanf("%lf%lf%lf",&p1->fenshu.China,&p1->fenshu.shuxue,&p1->fenshu.English); p1->fenshu.sum=p1->fenshu.China+p1->fenshu.shuxue+p1->fenshu.English; p1->fenshu.average=p1->fenshu.sum/3.0; printf("該學生資訊已修改成功\n"); printf("學生資訊已經新建成功,是否進行儲存? (Y/N)\n"); fflush(stdin); scanf("%c",&saveflag); if(saveflag=='y'||saveflag=='Y')//當輸入是的時候 Save(head); //呼叫儲存函式 else { printf("請按任意鍵返回主選單\n"); getch(); } break; } p1=p1->next; //p1指標向後移 } if(flag==0) //沒有這個名字的人,返回主選單 { printf("\n沒有找到要修改的學生資訊,請按任意鍵返回主選單!\n"); getch(); //按下任意鍵就進入下一條語句的函式 } return(head); } /************************************************ *函式名:Search(查詢) *功能:可以通過姓名查詢,也可以通過型別查詢 *返回值:NULL *************************************************/ void Search(ID *head) { int num; //子選單選擇 int count=0; ID* p; int flag; //flag是用來判斷是否找到, char c[10],searchflag='y';//c是來存放姓名或者型別, char ch[12]; while(1) { searchflag='y'; printf("\n**************查詢子選單*******************\n"); printf("\n\t 1.按姓名\n"); printf("\n\t 2.按學號\n"); printf("\n\t 3.返回主選單\n"); printf("\n*******************************************\n"); fflush(stdin); printf("請輸入您的選擇:\n"); scanf("%d",&num);//選擇你想要查詢的方式 switch(num) { case 1: while(searchflag=='y'||searchflag=='Y') { count=0; flag=0; //初始化為0 printf("\n請輸入待查詢的姓名: \n"); scanf("%8s",c); p=head; while(p!=NULL) { if(strcmp(p->name,c)==0) { count++; if(count==1) printf("\n學生姓名==學號=====性別===年齡==語文成績==數學成績==英語成績==總分==平均分\n\n"); printf("%-8s%-11s %-4s %-4d %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f \n",p->name,p->sno,p->sex,p->age,p->fenshu.China,p->fenshu.shuxue,p->fenshu.English,p->fenshu.sum,p->fenshu.average); flag=1; //flag賦值為1,表示為已經查到了資料了 } p=p->next; //p1指標向後移 } if(flag==0) //表示沒有找到相關資料 { printf("\n未能找到符合條件的記錄\n"); } else printf("\n\n\######找到了%d個姓名為\"%s\"學生!#####\n\n",count,c); printf("\n查詢完畢,是否需要重新查詢? (Y/N)\n"); fflush(stdin); scanf("%c",&searchflag);//是否繼續查詢(Y/N) } break; case 2: while(searchflag=='y'||searchflag=='Y') { count=0; flag=0; //初始化為0, printf("\n請輸入被查詢人的學號: \n"); scanf("%11s",ch); p=head; while(p!=NULL) { if(strcmp(p->sno,ch)==0) { count++; if(count==1) printf("\n學生姓名==學號=====性別===年齡==語文成績==數學成績==英語成績==總分==平均分\n\n"); printf("%-8s%-11s %-4s %-4d %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f \n",p->name,p->sno,p->sex,p->age,p->fenshu.China,p->fenshu.shuxue,p->fenshu.English,p->fenshu.sum,p->fenshu.average); flag=1; //flag賦值為1,表示為已經查到了資料了 } p=p->next; //p1指標向後移 } if(flag==0) //表示沒有找到相關資料 { printf("\n對不起,未能找到符合條件的記錄\n"); } else printf("\n\n\######找到了該學生!#####\n\n"); printf("\n查詢完畢,是否需要重新查詢? Y/N\n"); fflush(stdin); scanf("%c",&searchflag);//是否繼續查詢(Y/N) } break; case 3:return; default :printf("你輸入錯了,請你輸入任意鍵返回主選單...\n"); getch(); } } } /************************************************ *函式名: Delete(刪除) *功能:通過查詢學號來實現刪除學生記錄 *返回值:ID *(結構體指標) *************************************************/ ID* Delete(ID *head) { ID *p1,*p2; //p1是用來遍歷整一個單鏈表定位要刪除的結點,p2是用來定位p1的前結點的 char saveflag='n', temp; //saveflag是否儲存,temp是否刪除 char s[12]; //存放輸入的學號 p1=p2=head; //把head賦給p1,p2 printf("\n請輸入要刪除的學號:\n"); scanf("%11s",s); getchar(); while(p1!=NULL)//這個while語句的作用是在遍歷整個單鏈表時,當遇到一樣的名字時把i賦值,引導下面的工作 { if(strcmp(p1->sno,s)==0)//判斷是不是你輸入的名字是不是和學生資訊中的相等 { printf("你要刪除的學生為:\n"); printf("\n學生姓名==學號=====性別===年齡==語文成績==數學成績==英語成績==總分==平均分\n\n"); printf("%-8s%-11s %-4s %-4d %-8.2f %-8.2f %-8.2f %-8.2f %-8.2f \n",p1->name,p1->sno,p1->sex,p1->age,p1->fenshu.China,p1->fenshu.shuxue,p1->fenshu.English,p1->fenshu.sum,p1->fenshu.average); printf("請確定是否要刪除該記錄?Y/N?\n"); fflush(stdin); scanf("%c",&temp);//確定要刪除嗎? if(temp=='y'||temp=='Y')//當輸入是的時候 { if(p1==head)//判斷是不是在頭結點 head=p1->next;//把頭結點去掉 else p2->next=p1->next;//刪除p1結點(p2的next域指向p1的下個結點) printf("該學生資訊已刪除成功,是否存檔?Y/N?\n"); fflush(stdin); scanf("%c",&saveflag);//確定要儲存嗎? if(saveflag=='y'||saveflag=='Y')//當輸入是的時候 Save(head); //呼叫儲存函式 else { printf("請按任意鍵返回主選單\n"); getch(); } } else { printf("請按任意鍵返回主選單\n"); getch(); } break; } p2=p1; p1=p1->next; //p1指標向後移 } if((p1->next)==NULL&&strcmp(p1->sno,s)) { printf("沒有找到要刪除的學生學號,請檢查你要刪除的學號是否正確\n"); printf("請按任意鍵返回主選單\n"); getch(); //按下任意鍵就進入下一條語句的函式 } return(head); //return一個已經完成修改的連結串列頭指標 } /************************************************ *函式名: Swap(交換) *功能:交換結點內資料 *返回值:無 *************************************************/ void Swap1(char t1[],char t2[]) { char t[20]={0}; strcpy(t,t1); strcpy(t1,t2); strcpy(t2,t); } void Swap2(double s1,double s2) { double s; s=s1; s1=s2; s2=s; } void Swap3(int r1,int r2) { int r; r=r1; r1=r2; r2=r; } /************************************************ *函式名: Sort(排序) *功能:按照型別排序通訊記錄 *返回值:ID *(結構體指標) *************************************************/ void Sort(ID *head) { ID *p1,*p2; char saveflag='y'; p2=NULL; while( head != p2) { p1 = head; while( p1->next!= p2 ) { if( strcmp(p1->sno,p1->next->sno)>0) { Swap1(p1->name,p1->next->name); Swap1(p1->sno,p1->next->sno); Swap1(p1->sex ,p1->next->sex ); Swap2(p1->fenshu.China,p1->next->fenshu.China); Swap2(p1->fenshu.shuxue,p1->next->fenshu.shuxue); Swap2(p1->fenshu.English,p1->next->fenshu.English); Swap2(p1->fenshu.sum,p1->next->fenshu.sum); Swap2(p1->fenshu.average,p1->next->fenshu.average); Swap3(p1->age,p1->next->age); } p1 = p1->next; } p2= p1; } printf("學生已按照 學號型別 排序成功,是否存檔?Y/N?\n"); fflush(stdin); scanf("%c",&saveflag);//確定要儲存嗎? if(saveflag=='y'||saveflag=='Y')//當輸入是的時候 Save(head); //呼叫儲存函式 }