北 京 林 業 大 學
2020學年—2021學年第1學期 程式設計基礎課程設計 實習報告書
實習內容: 高校教師工資管理系統
實習環境: Sublime Text 3
目錄
一、實習步驟
二、實作方法概述
三、技術方案實作
3.0 資料存盤結構
3.0.0本地存盤結構(**創新點**)
3.0.1 教師資訊結構體 及 學院職稱映射陣列
3.0.2 薪資資訊結構體
3.0.3 學院平均值統計結構體 與 職稱平均值統計結構體
3.1 Operation Functions 概述
3.2 Check Functions 概述
3.2.1 checkten()--對輸入的數字范圍進行檢測
3.2.2 checkdb()--檢測用戶輸入是否為實數
3.2.3 checkid()--檢測用戶輸入id是否合法且合規
3.2.4 checkname()--檢測用戶名字是否存在
3.2.5 checkmon()--用以檢測所要查詢的月份是否存在salary資訊中
3.3 Storage Functions 概述
3.3.1 inpter() inpsal()--ter輸入函式 與 sal輸入函式
3.3.2 delter() delsal()--洗掉教師資訊及薪資資訊
3.3.3 自定義簡便SQL操作
3.4 Algorithm Functions 概述
3.4.1 showter()--可選mode的教師資訊串列列印函式
3.4.2 searchterid() searchsalid()--尋找所傳id對應的實際索引以便后續操作
3.4.3 swapter()swapsal()swapcol()swapjob()--交換函式
3.4.4 sortter_id() sortsal_id()--排序函式
3.4.5 calcolavg_sort() caljobavg_sort()--實作統計分析排序功能的函式
3.4.6 FreshSalName()--同步sal與ter之間的資訊
四、結果展示:
4.0開始界面
4.1進入錄入資料并保存功能
4.1.1教師資訊錄入功能
4.1.2錄入教師工資資訊
4.1.3 保存到本地功能
4.2 進入修改資料并保存功能
4.2.1 根據工號修改某位教師的基本資訊和工資資訊
4.2.2 根據姓名修改某位教師的基本資訊和工資資訊
4.2.3 洗掉某一工號的教師的所有資訊
4.3查詢顯示功能
4.3.1展示所有教師的基本資訊
4.3.2根據月份顯示所有教師當月工資資訊(以工號為序)
4.3.3根據工號查詢某位教師某一月份的基本資訊和工資資訊
4.3.4根據姓名查詢某位教師某一月份的基本資訊和工資資訊
4.4統計分析
4.4.1根據月份,統計不同學院教師的平均應發工資和平均實發工資
4.4.2根據月份,統計不同職稱教師的平均應發工資和平均實發工資
4.5從本地匯入資料(**創新點**)
4.6保存并退出功能
五、結束語:
一、實習步驟:
我于第一天進行該專案的整體分析及技術方案的選擇,第二天進行該程式的編碼作業,第三天進行程式的測驗作業和報告的書寫作業,
二、實作方法概述:
根據要求,該程式完全基于C語言實作,未使用任何外部庫檔案,代碼全部手敲完成,無任何借鑒復制行為,且撰寫代碼的全程序已錄制視頻,并將快放版上傳至B站:其地址為:https://www.bilibili.com/video/BV1Af4y1e7Tc/
該程式按照實驗要求分為五大模塊,完全實作實驗要求的所有功能,存盤在程式內采用結構體的方式,由于禁止使用SQL庫函式,所以我自己手寫了一套簡化版的SQL生成與決議函式,用于程式在本地的存盤結構(可實作對之前資料,或樣例資料的匯入),
設計采用自頂向下的方式,將每個大問題細化為各個小問題,將需要重復用到的解決方案演算法生成為可選擇模式的函式(如4.0.1 showter()),以達到簡化代碼量且提高可移植性的目標,每完成一個小模塊便進行測驗,以確保程式的正確性,
本系統系統功能結構

三、技術方案實作:
該程式的函式功能分為四大模塊,接下來將一一介紹,
3.0 資料存盤結構
3.0.0本地存盤結構(**創新點**)
由于該專案禁止使用SQL資料庫的相關庫檔案,我自己寫了一套類似于SQL存盤結構的生成函式及解釋函式,其于本地存盤的樣式類似于SQL中的insert values()陳述句,
- (0000000001,wu zheng,3,2)
- (0000000003,qian,3,2)
- (0000000001,wu zheng,3,2,2,200.00,100.00,56.00,300.00,244.00)
- (0000000001,wu zheng,3,2,3,45.00,6.00,6.00,51.00,45.00)
接下來將首先介紹該簡化SQL的生成方法
- void savetolocter()
- {
- // (id,name,colid,jobid)
- FILE * f1;
- f1=fopen("terdata.dat","w+");
- if(f1==NULL){printf("save to local unaviliable\n");return;}
- int i;
- for(i=0;i<tercnt;i++)
- {
- char tline[101]="(", tnum[5];
- strcat(tline,ter[i].id);
- strcat(tline,",");
- strcat(tline,ter[i].name);
- strcat(tline,",");
- strcat(tline,itoa(ter[i].collegeid,tnum,10));
- strcat(tline,",");
- strcat(tline,itoa(ter[i].jobid,tnum,10));
- strcat(tline,")");
- fprintf(f1, "%s\n", tline);
- }
- fclose(f1);
- }
- void savetolocsal()
- {
- FILE * f1;
- f1=fopen("saldata.dat","w+");
- if(f1==NULL){printf("save to local unaviliable\n");return;}
- int i;
- for(i=0;i<salcnt;i++)
- {
- char tline[201]="(", tnum[12];
- strcat(tline,sal[i].id);
- strcat(tline,",");
- strcat(tline,sal[i].name);
- strcat(tline,",");
- strcat(tline,itoa(sal[i].collegeid,tnum,10));
- strcat(tline,",");
- strcat(tline,itoa(sal[i].jobid,tnum,10));
- strcat(tline,",");
- strcat(tline,itoa(sal[i].month,tnum,10));
- strcat(tline,",");
- strcat(tline,d2s(sal[i].basicsal,tnum));
- strcat(tline,",");
- strcat(tline,d2s(sal[i].addsal,tnum));
- strcat(tline,",");
- strcat(tline,d2s(sal[i].subsal,tnum));
- strcat(tline,",");
- strcat(tline,d2s(sal[i].theosal,tnum));
- strcat(tline,",");
- strcat(tline,d2s(sal[i].truesal,tnum));
- strcat(tline,")");
- fprintf(f1, "%s\n", tline);
- }
- fclose(f1);
- }
其核心思想為模擬SQL的資料以逗號為分割的方式,將資料行通過fprintf結構化的存入到檔案中,以便后續的讀取,
接下來將介紹該SQL陳述句的決議函式
- void loadlocter(char * loc)
- {
- FILE * f1;
- f1=fopen(loc,"r");
- if(f1==NULL){printf("load to here unaviliable\n");return;}
- tercnt=0;
- char tinp[100];
- while(fgets(tinp,300,f1)!=NULL && tinp[0]!=10)
- {
- char tid[11],tna[31];
- int tcd,tjd;
- int i;
- for(i=1;i<=10;i++) tid[i-1]=tinp[i];
- int tcnt=0;
- for(i=12;tinp[i]!=',';i++) tna[tcnt++]=tinp[i];
- tna[tcnt]='\0';
- tcd=atoi(&tinp[i+1]);
- tjd=atoi(&tinp[i+3]);
- strcpy(ter[tercnt].id,tid);
- strcpy(ter[tercnt].name,tna);
- ter[tercnt].collegeid=tcd;
- ter[tercnt].jobid=tjd;
- tercnt++;
- //(1234567890,de d,1,1)
- }
- fclose(f1);
- sortter_id();
- }
- void loadlocsal(char * loc)
- {
- FILE * f1;
- f1=fopen(loc,"r");
- if(f1==NULL){printf("load to here unaviliable\n");return;}
- salcnt=0;
- char tinp[200];
- while(fgets(tinp,300,f1)!=NULL && tinp[0]!=10)
- {
- char tid[11],tna[31];
- int tcd,tjd;
- double t1,t2,t3,t4,t5;
- int i;
- for(i=1;i<=10;i++) tid[i-1]=tinp[i];
- int tcnt=0;
- for(i=12;tinp[i]!=',';i++) tna[tcnt++]=tinp[i];
- tna[tcnt]='\0';
- tcd=atoi(&tinp[++i]);i++;
- tjd=atoi(&tinp[++i]);i+=2;
- char tmon[4];tcnt=0;
- for(;tinp[i]!=',';i++) tmon[tcnt++]=tinp[i];
- tmon[tcnt]='\0';
- int mon=atoi(tmon);
- char tc[15];tcnt=0;
- for(i++;tinp[i]!=',';i++) tc[tcnt++]=tinp[i];
- tc[tcnt]='\0';t1=atof(tc);tcnt=0;
- for(i++;tinp[i]!=',';i++) tc[tcnt++]=tinp[i];
- tc[tcnt]='\0';t2=atof(tc);tcnt=0;
- for(i++;tinp[i]!=',';i++) tc[tcnt++]=tinp[i];
- tc[tcnt]='\0';t3=atof(tc);tcnt=0;
- for(i++;tinp[i]!=',';i++) tc[tcnt++]=tinp[i];
- tc[tcnt]='\0';t4=atof(tc);tcnt=0;
- for(i++;tinp[i]!=')';i++) tc[tcnt++]=tinp[i];
- tc[tcnt]='\0';t5=atof(tc);tcnt=0;
- strcpy(sal[salcnt].id,tid);
- strcpy(sal[salcnt].name,tna);
- sal[salcnt].collegeid=tcd;
- sal[salcnt].jobid=tjd;
- sal[salcnt].month=mon;
- sal[salcnt].basicsal=t1;
- sal[salcnt].addsal=t2;
- sal[salcnt].subsal=t3;
- sal[salcnt].theosal=t4;
- sal[salcnt].truesal=t5;
- salcnt++;
- }
- fclose(f1);
- }
其核心為檢測逗號所在位置,并以逗號為分割符,進行資料型別的轉換操作,最后復制到相應的變數中,
3.0.1 教師資訊結構體 及 學院職稱映射陣列
- struct Teacher{
- char id[11];
- char name[31];
- int collegeid;
- int jobid;
- }ter[NTer],tmpt; // use tmp to change
- int tercnt=0; // count the number of all teacher
- char col_sec[Ncol+1][31]={"","Information","Engineer","Theory","Arts","Biology"}; // college nubmer to name
- char job_sec[Njob+1][31]={"","Professor","Ass-Professor","Teacher","Tutor"}; // job nubmer to name
該段特殊采用數字映射字串的方法,將學院職稱皆量化為int,方便后續的操作,
3.0.2 薪資資訊結構體
- struct Salary{
- char id[11];
- char name[31];
- int collegeid;
- int jobid;
- int month;
- double basicsal, addsal, subsal, theosal, truesal;
- }sal[Nsal],tmps;
- int salcnt=0; // count the number of all records
basicsal—基本工資,addsal—業績津貼,subsal—扣除費用,theosal—應發工資,truesal—實發工資,
3.0.3 學院平均值統計結構體 與 職稱平均值統計結構體
- struct College
- {
- int collegeid;
- double thavg,travg;
- }col[6],tmpc;
- struct Job
- {
- int jobid;
- double thavg,travg;
- }job[6],tmpj;
進行統計分析時使用,
3.1 Operation Functions 概述
該部分代碼實作了程式與外接互動的全部功能,負責讀取用戶的操作輸入,并與用戶進行互動, 該部分具體內容將在【四】中進行演示并介紹,
3.2 Check Functions 概述
該部分代碼對實作程式魯棒性檢測及排除起到了重要作用,下面將依次介紹其實作方案,
3.2.1 checkten()--對輸入的數字范圍進行檢測
(應用于用戶選單選擇等)
- int checkten(int L,int R)
- {
- char opeinp[20];
- scanf("%s",opeinp);
- while ((atoi(opeinp)) == 0 or (atoi(opeinp)) > R or (atoi(opeinp)) < L )
- {
- printf("your input is invalid,please input again(just number from %d to %d):____\b\b\b",L,R);
- scanf("%s",opeinp);
- }
- return atoi(opeinp);
- }
通過atoi函式實作輸入字串向int型別的轉換作業,并判斷其大小范圍是否在給定的[L,R]區間內,如果非數字,或非所需區間,則給出提示并反復要求用戶輸入,直至用戶輸入合法,回傳該數值,
3.2.2 checkdb()--檢測用戶輸入是否為實數
(用于工資輸入的魯棒性檢查)
- double checkdb()
- {
- char opeinp[20];
- scanf("%s",opeinp);
- while ((atof(opeinp)) == 0)
- {
- printf("your input is invalid,please input again(just a real number):________\b\b\b\b\b\b\b\b");
- scanf("%s",opeinp);
- }
- return atof(opeinp);
- }
通過atof函式,將輸入字串轉換為double型別,如若轉換失敗(atof回傳值為0),則給出提示并反復要求用戶輸入,直至用戶輸入合法,回傳該數值,
3.2.3 checkid()--檢測用戶輸入id是否合法且合規
(用于id輸入的魯棒性檢查)
- void checkid(char * inpid, int judgeexist)
- {// if judgeexist == 1 , until input exist then return;
- // if judgeexist == 2 , until input not exist return;
- while(scanf("%s",inpid))
- {
- if(inpid[10] != '\0')
- { // check 10 digit to stop
- printf("your ID format is invalid,please make sure it is consist of 10 nubmers,ID:__________\b\b\b\b\b\b\b\b\b\b");
- continue;
- }
- int i;
- for(i = 0; i < 10; i++)
- {
- if(inpid[i] > '9' or inpid[0] < '0')
- {
- printf("your ID format is invalid,please make sure it is consist of 10 nubmers,ID:__________\b\b\b\b\b\b\b\b\b\b");
- break;
- }
- }
- if(i==10)
- { // format valid
- // to check existence
- int f=0; // 0 not exist; 1 exist
- for(i = 0;i < tercnt; i++)
- {
- if(strcmp(ter[i].id, inpid) == 0)
- {
- f=1;
- //printf("your ID input is existed, please make sure it's new one's id,ID:__________\b\b\b\b\b\b\b\b\b\b");
- break;
- }
- }
- if(judgeexist==1)
- {
- if(f==0)
- {
- printf("your ID input is not existed, please make sure it's above one's id,ID:__________\b\b\b\b\b\b\b\b\b\b");
- continue;
- }
- if(f==1)
- {
- return ;
- }
- }
- if(judgeexist==2)
- {
- if(f==1)
- {
- printf("your ID input is existed, please make sure it's new one's id,ID:__________\b\b\b\b\b\b\b\b\b\b");
- continue;
- }
- if(f==0)
- {
- return ;
- }
- }
- }
- }
- return ; // no use,just done for warning
- }
該函式6-10行判斷輸入是否為10位,10位判斷合法后,進入每位是否為數字的判斷,再次合法后,才將進入可選mode的判斷,
該函式我設定為可選mode,如果judgeexist == 1 ,則直到所輸入id存在于系統中才會回傳,如果judgeexist == 1 ,則直到所輸入id是不事先存在的才會回傳,該實作有利于后續的實際操作
3.2.4 checkname()--檢測用戶名字是否存在
(用于檢索名字時的魯棒性檢測)
- int checkname(char * inpname)
- {
- int t=0;
- rewind(stdin);
- while(1)
- {
- gets(inpname);
- rewind(stdin);
- int i;
- for(i=0;i<tercnt;i++)
- {
- if(strcmp(ter[i].name,inpname) == 0)
- {
- return 1;
- }
- }
- printf("your name input is not existed, please make sure it's above one's name,NAME:__________\b\b\b\b\b\b\b\b\b\b");
- t++;
- if(t==5) break;
- }
- return 0;
- }
該函式將遍歷整個ter結構體內的所有name,直至有匹配才回傳,如若一直未匹配,則證明不存在該名字,故提示用戶重新輸入,
3.2.5 checkmon()--用以檢測所要查詢的月份是否存在salary資訊中
- int checkmon(int * mon,char * id)
- {
- int t=1; // tried too many times
- while(1)
- {
- t++;
- if(searchsalid(id,*mon)!=-1) return 1;
- printf("%d month do not have salary information\n",*mon);
- printf("please resure and then INPUT:_____\b\b\b");
- *mon=checkten(1,12);
- if(t==5) break;
- }
- return 0;
- }
通過呼叫searchsalid 并進行匹配實作(后續將介紹該函式)
3.3 Storage Functions 概述
這些函式實作了資料的錄入,修改,洗掉,以及本地化SQL存盤等功能,
接下來將一一介紹,
3.3.1 inpter() inpsal()--ter輸入函式 與 sal輸入函式
- void inpter(int tid,int notfirst)
- {
- printf("Input the Teacher's NAME:______________\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
- rewind(stdin);
- gets(ter[tid].name); // to ignored the sperate by space
- printf("Input the college index of the teacher:\n1.Information,2.Engineer,3.Theory,4.Art,5.Biology. INPUT:___\b\b");
- ter[tid].collegeid=checkten(1,5);
- printf("Input the job index of the teacher:\n1.Professor,2.Ass-Professor,3.Teacher,4.Tutor. INPUT:___\b\b");
- ter[tid].jobid=checkten(1,4);
- struct Salary * sa;
- for(sa=sal;sa<sal+salcnt;sa++)
- {
- if(strcmp(sa->id,ter[tid].id)==0)
- {
- strcpy(sa->name,ter[tid].name);
- sa->jobid = ter[tid].jobid;
- sa->collegeid = ter[tid].collegeid;
- }
- }
- if(notfirst == 0) tercnt++;
- showter(3,ter[tid].id);
- if(notfirst == 0) tercnt--;
- printf("BELOW INFORMATION SAVED SUCCESSFULly \n");
- printf("PRESS ENTER TO CONTINUE.\n");getchar();getchar();
- }
- void inpsal(int sid,int notfirst)
- {
- printf("please input the month(nubmer from 1 to 12):______\b\b\b");
- sal[sid].month=checkten(1,12);
- printf("please input the basic salary:________\b\b\b\b\b\b\b\b");
- sal[sid].basicsal=checkdb();
- printf("please input the additional salary:________\b\b\b\b\b\b\b\b");
- sal[sid].addsal=checkdb();
- printf("please input the subtract salary:________\b\b\b\b\b\b\b\b");
- sal[sid].subsal=checkdb();
- sal[sid].theosal=sal[sid].basicsal+sal[sid].addsal;
- sal[sid].truesal=sal[sid].theosal-sal[sid].subsal;
- FreshSalName(sid);
- if(notfirst == 0) salcnt++;
- showsal(3,sal[sid].id,sal[sid].month);
- if(notfirst == 0) salcnt--;
- printf("BELOW INFORMATION SAVED SUCCESSFULlY \n");
- printf("PRESS ENTER TO CONTINUE.\n");getchar();getchar();
- }
該段代碼實作了排除魯棒性的輸入功能,并將教師資訊中的姓名,學院,職稱等,(如果工資資訊存在)更新給工資資訊,且在輸入完成后,顯示最新資訊,以便查驗,
3.3.2 delter() delsal()--洗掉教師資訊及薪資資訊
- void deleteter(char * id)
- {
- // through swap and cnt-- to complete the delete operation
- swapter(&ter[tercnt-1],&ter[searchterid(id)]);
- tercnt--;
- }
- void deletesal(char * id)
- {
- int i;
- for(i=0;i<salcnt;i++)
- {
- if(strcmp(sal[i].id,id) == 0)
- {
- swapsal(&sal[i],&sal[salcnt-1]);
- salcnt--;
- }
- FreshSalName(i); // to check bug
- }
- }
該洗掉方法為:交換當前元素和最后一位元素的全部資訊(通過自定swap實作,后續將進行介紹),并將總元素個數的統計變數減一,以此實作該洗掉操作,
3.3.3 自定義簡便SQL操作
已在3.0.0中介紹完畢,此處不再贅述,
3.4 Algorithm Functions 概述
該部分實作該程式的主要演算法功能,接下來將一一介紹各函式的實作方法,
3.4.1 showter()--可選mode的教師資訊串列列印函式
- int showter(int mode,char * cc)
- { // mode == 1: show all information
- // mode == 2: show NAME(tc)'s infromation
- // mode == 3: show ID(tc)'s information
- int re=-1;
- struct Teacher * tc;
- printf("\n---------------------------Basic Information---------------------\n");
- printf("|ID\t\t|NAME\t\t|COLLEGE\t|JOB\t\t|\n");
- printf("-----------------------------------------------------------------\n");
- for(tc=ter;tc<ter+tercnt;tc++)
- {
- if(mode == 1) printf("|%s\t|%-15s|%-15s|%-15s|\n",tc->id,tc->name,col_sec[tc->collegeid],job_sec[tc->jobid]);
- if(mode == 2 && (strcmp(tc->name,cc) == 0) ) printf("|%s\t|%-15s|%-15s|%-15s|\n",tc->id,tc->name,col_sec[tc->collegeid],job_sec[tc->jobid]);
- if(mode == 3 && (strcmp(tc->id,cc) == 0) )
- {
- re=tc-ter; // return his cntid
- printf("|%s\t|%-15s|%-15s|%-15s|\n",tc->id,tc->name,col_sec[tc->collegeid],job_sec[tc->jobid]);
- }
- }
- printf("-----------------------------------------------------------------\n\n");
- return re;
- }
- void showsal(int mode,char * cc,int mon)
- { // mode == 1: show all information
- // mode == 2: show NAME(tc)'s infromation
- // mode == 3: show ID(tc)'s information
- // if mon == 0 then cout every information
- // if mon == 1~12 then just cout the month's information
- struct Salary * sa;
- printf("\n-------------------------------------------------Salary Information------------------------------------------------------\n");
- printf("|Month\t|ID\t\t|NAME\t\t|Basic($)\t|Allowance($)\t|Subtract($)\t|Theory($)\t|True($)\t|\n");
- printf("-------------------------------------------------------------------------------------------------------------------------\n");
- for(sa=sal;sa<sal+salcnt;sa++)
- {
- if(mode == 1 && (mon==0?1:sa->month==mon)) printf("|%d\t|%-15s|%-15s|%-15.2f|%-15.2f|%-15.2f|%-15.2f|%-15.2f|\n",sa->month,sa->id,
- sa->name,sa->basicsal,sa->addsal,sa->subsal,sa->theosal,sa->truesal);
- if(mode == 2 && (strcmp(sa->name,cc) == 0) && (mon==0?1:(sa->month==mon))) printf("|%d\t|%-15s|%-15s|%-15.2f|%-15.2f|%-15.2f|%-15.2f|%-15.2f|\n",sa->month,sa->id,
- sa->name,sa->basicsal,sa->addsal,sa->subsal,sa->theosal,sa->truesal);
- if(mode == 3 && (strcmp(sa->id,cc) == 0) && (mon==0?1:(sa->month==mon))) printf("|%d\t|%-15s|%-15s|%-15.2f|%-15.2f|%-15.2f|%-15.2f|%-15.2f|\n",sa->month,sa->id,
- sa->name,sa->basicsal,sa->addsal,sa->subsal,sa->theosal,sa->truesal);
- }
- printf("-------------------------------------------------------------------------------------------------------------------------\n\n");
- }
當mode為1時,將展示所有教師的基本資訊或薪水資訊;當mode為2時,將展示姓名為所傳入引數的教師的基本資訊或薪水資訊;當mode為3時,將展示ID為所傳入引數的教師基本資訊或薪水資訊,
并且該函式利用了printf的格式化輸出功能,保證串列的整齊與美觀,

3.4.2 searchterid() searchsalid()--尋找所傳id對應的實際索引以便后續操作
- int searchterid(char * id)
- {
- int i;
- for(i=0; i < tercnt;i++)
- {
- if(strcmp(ter[i].id,id)== 0) return i;
- }
- return -1;
- }
- int searchsalid(char * id,int month)
- {
- int i;
- for(i=0;i<salcnt;i++)
- {
- if(strcmp(id,sal[i].id)==0 && sal[i].month == month) return i;
- }
- return -1;
- }
額外地,在考慮查詢月份需求的情況下,特假設month引數,以選擇特定的month進行輸出(給定 month和id時才能唯一的確定一條記錄),
3.4.3 swapter()swapsal()swapcol()swapjob()--交換函式
全部內容交換函式,通過臨時變數交換法實作,此處不做贅述,
3.4.4 sortter_id() sortsal_id()--排序函式
以id為序,對ter和sal的排序函式
- void sortter_id()
- { // make the ter list sorted by the id
- int i,j;
- for(i=0;i<tercnt;i++)
- for(j=tercnt-1;j>i;j--)
- if(strcmp(ter[j].id,ter[j-1].id)<0)
- swapter(&ter[j],&ter[j-1]);
- }
- void sortsal_id()
- { // make the sal list sorted by the 1:id 2:month
- int i,j;
- for(i=0;i<salcnt;i++)
- for(j=salcnt-1;j>i;j--)
- {
- if(strcmp(sal[j].id,sal[j-1].id)<0)
- swapsal(&sal[j],&sal[j-1]);
- if(strcmp(sal[j].id,sal[j-1].id) == 0)
- if(sal[j].month < sal[j-1].month)
- swapsal(&sal[j],&sal[j-1]);
- }
- }
由于禁止使用C++的algorithm庫及其sort函式,以及bool cmp() 排序規則,在此處我通過手寫的方式,實作了相應的功能,基于冒泡排序和前面的swap函式實作,
3.4.5 calcolavg_sort() caljobavg_sort()--實作統計分析排序功能的函式
- void calcolavg_sort(int mon)
- {
- int i,j;
- for(i=1;i<=Ncol;i++)
- {
- double thsum=0,trsum=0,cnt=0; // th->theory tr->true
- for(j=0;j<salcnt;j++)
- {
- if(sal[j].collegeid == i && sal[j].month == mon)
- {
- thsum += sal[j].theosal;
- trsum += sal[j].truesal;
- cnt++;
- }
- }
- col[i].collegeid = i;
- col[i].thavg= thsum?thsum/cnt:0;
- col[i].travg= trsum?trsum/cnt:0;
- }
- for(i=1;i<=Ncol;i++)
- for(j=Ncol;j>i;j--)
- {
- if(col[j].travg > col[j-1].travg)
- swapcol(&col[j],&col[j-1]);
- if(col[j].travg == col[j-1].travg)
- if(sal[j].collegeid < sal[j-1].collegeid)
- swapcol(&col[j],&col[j-1]);
- }
- }
- void caljobavg_sort(int mon)
- {
- int i,j;
- for(i=1;i<=Njob;i++)
- {
- double thsum=0,trsum=0,cnt=0; // th->theory tr->true
- for(j=0;j<salcnt;j++)
- {
- if(sal[j].jobid == i && sal[j].month == mon)
- {
- thsum += sal[j].theosal;
- trsum += sal[j].truesal;
- cnt++;
- }
- }
- job[i].jobid = i;
- job[i].thavg= thsum?thsum/cnt:0;
- job[i].travg= trsum?trsum/cnt:0;
- }
- for(i=1;i<=Njob;i++)
- for(j=Njob;j>i;j--)
- {
- if(job[j].thavg > job[j-1].thavg)
- swapjob(&job[j],&job[j-1]);
- if(job[j].travg == job[j-1].travg)
- if(sal[j].jobid < sal[j-1].jobid)
- swapjob(&job[j],&job[j-1]);
- }
- }
該段程式通過對所選職業或學院的相應工資資訊進行累加,并存盤在job和college兩個結構體中,最后對這兩個結構體進行排序實作以上功能,
3.4.6 FreshSalName()--同步sal與ter之間的資訊
由于涉及到對salary資訊與teacher資訊的同步更新,設定此函式
- void FreshSalName(int salind)
- {
- int i;
- for(i=0; i<tercnt;i++)
- {
- if(strcmp(ter[i].id,sal[salind].id) == 0)
- {
- strcpy(sal[salind].name,ter[i].name);
- sal[salind].collegeid=ter[i].collegeid;
- sal[salind].jobid=ter[i].jobid;
- break;
- }
- }
- }
通過比對id后,進行賦值,實作相應功能,
四、結果展示:
4.0開始界面
展示軟體資訊及版本資訊

進行321的倒計數后,進入程式的主界面



進入操作主選單

魯棒性測驗(只有輸入給定的運算元才可繼續)

4.1進入錄入資料并保存功能

4.1.1教師資訊錄入功能
(錄入學號姓名等,并以代號形式錄入學院,職稱資訊)
最終將該資訊以串列的形式列印出來

魯棒性測驗4.1.1.1(教師id重復)
![]()
魯棒性測驗4.1.1.2(教師id出現特殊字符,id過長,id過短)

魯棒性測驗4.1.1.3(學院、職稱出現特殊字符,過長,過短)

4.1.2錄入教師工資資訊
按照提示錄入相應資訊后,將會輸出該調工資資訊(人性化互動)

4.1.2.1 魯棒性測驗(輸入不存在的id)
![]()
4.1.2.2 魯棒性測驗(輸入不合法的月份資訊)

4.1.2.3魯棒性測驗(輸入不合法的錢數資訊)

4.1.3 保存到本地功能

已成功存盤到結構體和本地的dat檔案中,

4.2 進入修改資料并保存功能

4.2.1 根據工號修改某位教師的基本資訊和工資資訊

修改基礎資訊:

修改工資資訊:

4.2.1.1魯棒性測驗(當月份資訊不存在時)

4.2.1.2魯棒性測驗(當多次輸入錯誤月份資訊時)--跳出避免死回圈

其他魯棒性繼承于前序操作,此處不再重復演示,
4.2.2 根據姓名修改某位教師的基本資訊和工資資訊
Case1:該姓名不重復

Case2:該姓名存在重復情況 – 選擇所需要選擇的id輸出即可

4.2.2.1魯棒性測驗(所輸入的名字不存在) -- 提示重新輸入
![]()
4.2.3 洗掉某一工號的教師的所有資訊
將所有資訊列出后,要求輸入所要洗掉人的id
經過多次確認后方可洗掉,洗掉后輸出最新的全部資訊表格

4.3查詢顯示功能

4.3.1展示所有教師的基本資訊

4.3.2根據月份顯示所有教師當月工資資訊(以工號為序)

4.3.3根據工號查詢某位教師某一月份的基本資訊和工資資訊

4.3.4根據姓名查詢某位教師某一月份的基本資訊和工資資訊
Case1:無重復時

Case2:有重復時

4.3.4.1魯棒性測驗(姓名不存在)
![]()
4.4統計分析

4.4.1根據月份,統計不同學院教師的平均應發工資和平均實發工資

4.4.2根據月份,統計不同職稱教師的平均應發工資和平均實發工資

4.5從本地匯入資料(**創新點**)
可選從上次存盤資料中匯入,或從演示樣例資料中進行匯入
![]()
匯入成功后,將顯示所匯入的資訊

4.6保存并退出功能
經過多次確認后方可退出

退出感謝資訊

五、結束語:
以上為該程式的全部實作方法及演示,代碼已傳至個人GitHub上,該專案地址為:https://github.com/ShuoCHN/SalaryManageSystem,如有任何疑問或發現存在bug,請加私信與我進行討論,謝謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/243886.html
標籤:其他
上一篇:定時器和中斷的關系,以及為什么應該盡量減少使用延時函式
下一篇:排序演算法第二談:快速排序
