【设计目的】

1、教学目的

本课程设计是学生学习完《C 语言程序设计》课程后,进行的一次全面的综合训练,通过课程设计,更好地掌握使用 C语言进行程序设计的方法,加深对C 语言特点和使用C 语言进行程序设计开发过程的理解,加强动手能力。其主要目的是:

(1)进一步培养学生C 语言程序设计的思想,加深对高级语言基本语言要素和控制结构的理解;

(2)针对C 语言中的重点和难点内容进行训练,独立完成有一定工作量的程序设计任务,同时强调好的程序设计风格。

(3)掌握C 语言的编程技巧和上机调试程序的方法。

(4)掌握程序设计的常用算法。

2、教学要求

(1)要求从所给题目中任选若干个,每个学生必须独立完成课程设计,不能互相抄袭。

(2)设计完成后,对所完成的工作进行答辩。

(3)要求写出一份详细的课程设计报告。

(4)程序设计题目,须提交相应的程序,并需提供加注释的源程序,能正常运行。

【需求分析】

1、问题

根据需求,该系统所应包含的信息有以下一些:

每个教师的信息为:

教师号、姓名、性别、单位名称、家庭住址、联系电话、

基本工资、津贴、生活补贴、应发工资、

电话费、水电费、房租、所得税、卫生费、公积金、合计扣款、实发工资。

根据需求,该系统所应实现的功能有以下一些:

一、教师信息处理:

(1)输入教师信息

(2)插入(修改)教师信息:

(3)删除教师信息

(4)浏览教师信息

二、教师数据处理:

(1)按教师号录入教师基本工资、津贴、生活补贴、电话费、水电费、房租、所得税、卫生费、公积金等基本数据。

(2)教师实发工资、应发工资、合计扣款计算。

1、应发工资=基本工资+津贴+生活补贴;

2、合计扣款=电话费+水电费+房租+所得税+卫生费+公积金;

3、实发工资=应发工资 - 合计扣款。

(3)教师数据管理

提示:输入新数据,将改后信息写入文件

(4)教师数据查询

提示:输入教师号或其他信息,即读出所有数据信息,并显示出来。

(5)教师综合信息输出

提示:输出教师信息到屏幕。

2、系统

采用C语言实现,可以运行在操作系统WINDOWS。

3、运行要求

能不受限制的录入教师数据信息。

界面友好,操作方便,例如删除、修改、查询等操作均可以选择根据教师号进行还是教师姓名进行,程序进行增删改查操作结束后,程序返回上一级菜单。

容错性强,例如输入添加教师信息时,会对教师号、电话号码、性别等进行校验,输入有误时会提示出错信息,程序不会异常终止,且程序处理了重名问题

【总体设计】

1、系统流程设计

根据系统要求,设计如图 1所示的流程图。

图 1- 系统流程

2、系统模块设计

根据系统的功能设计,如图 2所示。

图 2- 系统功能图

主界面模块:完成系统菜单的显示

功能选择模块:根据用户的选择,完成其相应的功能

添加教师信息:完成用户从界面输入教师信息,将教师数据信息录入到文件中。

删除教师信息:根据用户的输入,判断是根据教师号删除教师信息还是根据姓名删除教师信息,或是返回主页、退出程序。

根据教师号删除教师信息:完成用户从界面输入要删除的教师号,在系统查询符合条件的教师信息链表中的教师信息节点,在界面上输出该节点,询问用户是否确定删除。如果用户确定,则删除查询到的链表节点,并将链表再存放进文件;如果用户取消,则结束删除功能,返回上一级菜单;如果用户输入错误,则继续循环让用户选择确认/取消。

根据教师姓名删除教师信息:完成用户从界面输入要删除的教师姓名,在系统查询符合条件的教师信息链表中的教师信息节点,排除重名因素,在界面上输出该节点,询问用户是否确定删除。如果用户确定,则删除查询到的链表节点,并将链表再存放进文件;如果用户取消,则结束删除功能,返回上一级菜单;如果用户输入错误,则继续循环让用户选择确认/取消。

修改教师信息:完成根据用户的输入,判断是根据教师号修改教师信息还是根据姓名修改教师信息,或是返回主页、退出程序的功能。

根据教师号修改教师信息:完成用户从界面输入要修改的教师号,在系统查询符合条件的教师信息链表中的教师信息节点,在界面上输出该节点,询问用户是否确定修改。如果用户确定,则让用户从界面输入要修改的教师信息后,修改查询到的链表节点,并将链表再存放进文件;如果用户取消,则结束修改功能,返回上一级菜单;如果用户输入错误,则继续循环让用户选择确认/取消。

根据教师姓名修改教师信息:完成用户从界面输入要修改的教师姓名,在系统查询符合条件的教师信息链表中的教师信息节点,排除重名影响,在界面上输出该节点,询问用户是否确定修改。如果用户确定,则让用户从界面输入要修改的教师信息后,修改查询到的链表节点,并将链表再存放进文件;如果用户取消,则结束修改功能,返回上一级菜单;如果用户输入错误,则继续循环让用户选择确认/取消。

查询教师信息:根据用户的输入,判断是根据教师号查询教师信息还是根据姓名查询教师信息,或是按教师号顺序排序输出教师信息、按工资从低到高排序输出教师信息、或是返回主页、退出程序。

根据教师号查询教师信息:完成用户从界面输入要查询的教师号,在系统查询符合条件的教师信息链表,并在界面上显示的功能。

根据教师姓名查询教师信息:完成用户从界面输入要查询的教师姓名,在系统查询符合条件的教师信息链表,并在界面上显示的功能。

按教师号显示教师信息:完成用户从界面输入按行显示还是按列显示,按教师号从低到高显示全部教师信息的功能。

按工资(低->)显示教师信息:完成用户从界面输入按行显示还是按列显示,按工资从低到高显示全部教师信息的功能。

模块概要如图 3所示

图 3- 描述菜单对应的各函数大致执行的流程图

【详细设计】

1、数据结构设计

根据系统要求,系统中需要保存的数据有教师的数据信息,其结构如表 1所示。

表 1- 教师数据信息

数据项名称

数据项系统表示

数据类型

数据长度

备注

教师号

id

整型

姓名

name

字符串

20

性别

sex

字符串

5

单位名称

workPlace

字符串

100

家庭住址

address

字符串

100

联系电话

tel

字符串

20

基本工资

salary

浮点型

津贴

benefit

浮点型

生活补贴

livingAllowance

浮点型

应发工资

shouldPay

浮点型

电话费

telBill

浮点型

水电费

waterBill

浮点型

房租

rentPay

浮点型

所得税

incomeTax

浮点型

卫生费

cleanBill

浮点型

公积金

fund

浮点型

合计扣款

totalDeduct

浮点型

实发工资

realPay

浮点型

使用C语言创建的结构体如下:

typedef struct Teacher{int id;//教师号char name[20];//姓名char sex[5];//性别char workPlace[100];//单位名称char address[100];//家庭住址char tel[20];//联系电话float salary;//基本工资float benefit;//津贴float livingAllowance;//生活补贴float shouldPay;//应发工资float telBill;//电话费float warterBill;//水电费float rentPay;//房租float incomeTax;//所得税float cleanBill;//卫生费float fund;//公积金float totalDeduct;//合计扣款float realPay;//实发工资struct Teacher *pnext;} teacher;

2、界面设计

主界面:

根据系统要求,设计一个字符界面,显示系统的菜单,为了体现友好性,将在每个菜单前显示该菜单项对应的数字

用户输入菜单项前面的数字,主菜单消失,进入该模块的相应界面,进行相应的操作,完成后,回到主界面。

输入界面如图4所示。

图 4- 输入界面

添加教师信息界面如图 5所示。

图 5- 添加教师信息界面

删除教师信息界面如图 6示。

图 6- 删除教师信息界面

根据教师号删除教师信息界面如图 7示。

图 7- 根据教师号删除教师信息界面

根据教师姓名删除教师信息界面如图 8、图 9所示。

图 8- 根据教师姓名删除教师信息(有重名)界面

图 9- 根据教师姓名删除教师信息(无重名)界面

修改教师信息界面如图 10所示。

图 10- 修改教师信息界面

根据教师号修改教师信息界面如图 11所示。

图 11- 根据教师号修改教师信息界面

根据教师姓名修改教师信息界面如图 12、图 13所示。

图 12- 根据教师姓名修改教师信息界面(有重复)

图 13- 根据教师姓名修改教师信息

查询教师信息界面如图 14所示。

图 14- 查询教师信息界面

根据教师号查询教师信息界面如图 15所示。

图 15- 根据教师号查询教师信息界面

根据教师姓名查询教师信息界面如图 16所示。

图 16- 根据教师姓名查询教师信息界面

按教师号显示教师信息界面如图 17所示。

图 17- 按教师号显示教师信息界面

按工资(低->高)显示教师信息界面如图 18所示。

图 18- 按工资(低->高)显示教师信息界面

3、模块实现

(1)主界面实现

调用printf()函数,在屏幕上打印需要显示的字符信息。

(2)功能选择模块实现

接受从键盘输入的菜单选择,判断并调用相应的功能函数,完成其对应的功能。实现功能选择。

对应的函数:

void menu(){system("cls");char ch;printf("***************教师工资管理系统***************\n");printf("-------------------菜单列表-------------------\n");printf("* 1:添加教师信息 *\n");printf("* 2.删除教师信息 *\n");printf("* 3:修改教师信息 *\n");printf("* 4:查询教师信息 *\n");printf("* 0.退出程序 *\n");printf("**********************************************\n");do{printf("请选择:");ch = getchar();fflush(stdin);switch(ch){case '1':addNode();break;case '2':deleteNodeByIdOrName();break;case '3':editNodeByIdOrName();break;case '4':searchNodeByNameOrIdOrAll();break;case '0':exit(0);}}while(ch!='0');}

A.添加教师信息模块

模块说明:

用户从界面输入教师信息,将教师信息存放到新的新的链表结点中,并将存放教师数据信息的链表存放到文件中。

模块流程:

图 19- addNode()函数

对应函数:

void addNode(){system("cls");teacher *pnew;char ch;pnew=(teacher *)malloc(sizeof(teacher));printf("请输入教师信息:\n");printf("==========================================\n");do{printf("请输入教师号:");scanf("%d",&pnew->id);}while(check_number(pnew->id));printf("请输入教师姓名:");scanf("%s",&pnew->name);do{printf("请输入教师性别:");scanf("%s",&pnew->sex);}while(check_sex(pnew->sex));printf("请输入教师单位名称:");scanf("%s",&pnew->workPlace);printf("请输入教师家庭住址:");scanf("%s",&pnew->address);do{printf("请输入教师的电话号码:");scanf("%s",&pnew->tel);}while(check_tel(pnew->tel)); printf("==========================================\n");printf("请输入教师基本工资:");scanf("%f",&pnew->salary);printf("请输入教师的津贴:");scanf("%f",&pnew->benefit);printf("请输入教师的生活补贴:");scanf("%f",&pnew->livingAllowance);pnew->shouldPay=pnew->salary+pnew->benefit+pnew->livingAllowance;printf("========应发工资为:%.2f=============\n",pnew->shouldPay);printf("请输入教师的电话费:");scanf("%f",&pnew->telBill);printf("请输入教师的水电费:");scanf("%f",&pnew->waterBill);printf("请输入教师的房租:");scanf("%f",&pnew->rentPay);printf("请输入教师的所得税:");scanf("%f",&pnew->incomeTax);printf("请输入教师的卫生费:");scanf("%f",&pnew->cleanBill);printf("请输入教师的公积金:");scanf("%f",&pnew->fund);pnew->totalDeduct=pnew->telBill+pnew->waterBill+pnew->rentPay+pnew->incomeTax+pnew->cleanBill+pnew->fund;printf("========合计扣款为:%.2f=============\n",pnew->totalDeduct);pnew->realPay=pnew->shouldPay-pnew->totalDeduct;printf("==========实发工资为:%.2f=============\n",pnew->realPay);printf("==========================================\n");showNode(pnew);printf("==========================================\n");printf("确认录入该教师的信息吗(y/n):" />pnext=NULL;printf("录入成功!\n"); link_save(); printf("按任意键回到主菜单");getch();getchar();menu();return;}if(pHead->id>pnew->id){ teacher *pr=pHead; pHead=pnew; pHead->pnext=pr;}else{ teacher *p; teacher *bf; p=pHead; while(p->idid){bf=p;p=p->pnext;if(p==NULL){bf->pnext=pnew;pnew->pnext=NULL;printf("录入成功!\n"); link_save(); printf("\n-------按任意键回到主菜单--------"); getch(); getchar(); menu(); return;}}pnew->pnext=p;bf->pnext=pnew;} printf("录入成功!\n"); link_save();printf("\n-------按任意键回到主菜单--------"); getch(); getchar(); menu();}else{printf("确认录入该教师的信息吗(y/n):?\n");}} while(ch!='n'||ch!='y');}

B.删除教师信息模块

模块说明:

接受从键盘输入的菜单选择,判断并调用相应的功能函数,完成其对应的功能。实现功能选择。

对应函数:

void deleteNode(teacher *node){char ch;printf("------------以下是要删除的教师信息------------\n");showNode(node);printf("----------------------------------------------\n");printf("确定删除该信息吗(y/n):?\n");do{ch = getch();if(ch == 'n'){printf("取消成功!\n");printf("--------按任意键回到菜单---------\n"); getch(); deleteNodeByIdOrName(); return;}else if(ch =='y'){if(node->id==pHead->id){pHead=pHead->pnext;free(node);}else if(node->pnext==NULL){teacher *k;k=pHead;while(k->pnext!=node){k=k->pnext;}k->pnext=NULL;}else{teacher *d=pHead;while(d->pnext!=node){d=d->pnext;}d->pnext=node->pnext;}link_save();printf("---------删除成功!---------------\n");printf("--------按任意键回到菜单---------\n"); getch(); deleteNodeByIdOrName();return;}else{printf("确定删除该信息吗(y/n):?\n");}} while(ch!='n'||ch!='y'); }

(a)根据教师号删除教师信息

模块说明:

完成用户从界面输入要删除的教师号,在系统查询符合条件的教师信息链表中的教师信息节点,在界面上输出该节点,询问用户是否确定删除。如果用户确定,则删除查询到的链表节点,并将链表再存放进文件;如果用户取消,则结束删除功能,返回上一级菜单;如果用户输入错误,则继续循环让用户选择确认/取消。

模块流程:

图 20- deleteNodeById()函数

对应程序:

find=findLinkById();if(find!=NULL){deleteNode(find);}else{printf("系统中没有找到此教师\n");printf("--------按任意键回到菜单---------\n");getch();deleteNodeByIdOrName();}

(b)根据教师姓名删除教师信息

模块说明:

用户从界面输入要删除的教师姓名,在系统查询符合条件的教师信息链表中的教师信息节点,排除重名因素,在界面上输出该节点,询问用户是否确定删除。如果用户确定,则删除查询到的链表节点,并将链表再存放进文件;如果用户取消,则结束删除功能,返回上一级菜单;如果用户输入错误,则继续循环让用户选择确认/取消。

模块流程:

图 21- deleteNodeByName()函数

对应程序:

printf("请输入教师姓名:");scanf("%s",&name);nodes=findNodesByName(name,copyLink(pHead));if(link_length(nodes)==1){find=findLinkByName(nodes->name);deleteNode(find);break;}else if(link_length(nodes)>1){printf("有教师重名,删除失败!\n重名结果如下:\n");printf("==========================================\n");showLinkByRow(nodes);printf("==========================================\n");printf("\n提示:请根据教师号删除\n\n");printf("--------按任意键回到菜单---------\n");getch();deleteNodeByIdOrName();break;break;}else{printf("系统中没有找到此教师\n");printf("--------按任意键回到菜单---------\n");getch();deleteNodeByIdOrName();break;}

C.修改教师信息模块

模块说明:

根据用户的输入,判断是根据教师号修改教师信息还是根据姓名修改教师信息,或是返回主页、退出程序。

对应函数:

void editNode(teacher *node){char ch;printf("------------以下是要修改的教师信息------------\n");showNode(node);printf("----------------------------------------------\n");printf("确定修改该信息吗(y/n):?\n");do{ch = getch();if(ch == 'n'){printf("取消成功!\n");printf("--------按任意键回到菜单---------\n"); getch(); editNodeByIdOrName(); return;}else if(ch =='y'){printf("请重新输入以下信息:\n");printf("==========================================\n");printf("请输入教师姓名:");scanf("%s",&node->name);printf("请输入教师性别:");scanf("%s",&node->sex);printf("请输入教师单位名称:");scanf("%s",&node->workPlace);printf("请输入教师家庭住址:");scanf("%s",&node->address);printf("请输入教师的电话号码:");scanf("%s",&node->tel);printf("==========================================\n");printf("请输入教师基本工资:");scanf("%f",&node->salary);printf("请输入教师的津贴:");scanf("%f",&node->benefit);printf("请输入教师的生活补贴:");scanf("%f",&node->livingAllowance);node->shouldPay=node->salary+node->benefit+node->livingAllowance;printf("=========应发工资为:%.2f==========\n",node->shouldPay);printf("请输入教师的电话费:");scanf("%f",&node->telBill);printf("请输入教师的水电费:");scanf("%f",&node->waterBill);printf("请输入教师的房租:");scanf("%f",&node->rentPay);printf("请输入教师的所得税:");scanf("%f",&node->incomeTax);printf("请输入教师的卫生费:");scanf("%f",&node->cleanBill);printf("请输入教师的公积金:");scanf("%f",&node->fund);node->totalDeduct=node->telBill+node->waterBill+node->rentPay+node->incomeTax+node->cleanBill+node->fund;printf("========合计扣款为:%.2f==========\n",node->totalDeduct);node->realPay=node->shouldPay-node->totalDeduct;printf("========实发工资为:%.2f===========\n",node->realPay);printf("==========================================\n");link_save();printf("---------修改成功!---------------\n");printf("--------按任意键回到菜单---------\n"); getch(); editNodeByIdOrName();return;}else{printf("确定修改该信息吗(y/n):?\n");}} while(ch!='n'||ch!='y');}

(a)根据教师号修改教师信息

模块说明:

从界面输入要修改的教师号,在系统查询符合条件的教师信息链表中的教师信息节点,在界面上输出该节点,询问用户是否确定修改。如果用户确定,则让用户从界面输入要修改的教师信息后,修改查询到的链表节点,并将链表再存放进文件;如果用户取消,则结束修改功能,返回上一级菜单;如果用户输入错误,则继续循环让用户选择确认/取消。

模块流程:

图 22- editNodeById()函数

对应程序:

find=findLinkById();if(find!=NULL){editNode(find);}else{printf("系统中没有找到此教师\n");printf("--------按任意键回到菜单---------\n");getch();editNodeByIdOrName();}

(b)根据教师姓名修改教师信息

模块说明:

用户从界面输入要修改的教师姓名,在系统查询符合条件的教师信息链表中的教师信息节点,排除重名影响,在界面上输出该节点,询问用户是否确定修改。如果用户确定,则让用户从界面输入要修改的教师信息后,修改查询到的链表节点,并将链表再存放进文件;如果用户取消,则结束修改功能,返回上一级菜单;如果用户输入错误,则继续循环让用户选择确认/取消。

模块流程:

图 23- editNodeByName()函数

对应程序:

printf("请输入教师姓名:");scanf("%s",&name);nodes=findNodesByName(name,copyLink(pHead));if(link_length(nodes)==1){find=findLinkByName(nodes->name);editNode(find);break;}else if(link_length(nodes)>1){printf("有教师重名,修改失败!\n重名结果如下:\n");printf("==========================================\n");showLinkByRow(nodes);printf("==========================================\n");printf("\n提示:请根据教师号修改\n\n");printf("--------按任意键回到菜单---------\n");getch();editNodeByIdOrName();break;}else{printf("系统中没有找到此教师\n");printf("--------按任意键回到菜单---------\n");getch();editNodeByIdOrName();break;}

D.查询教师信息模块

模块说明:

根据用户的输入,判断是根据教师号查询教师信息还是根据姓名查询教师信息,或是按教师号顺序排序输出教师信息、按工资从低到高排序输出教师信息、或是返回主页、退出程序。

对应函数:

teacher * findLinkById(){int id;printf("请输入教师号:");scanf("%d",&id);if(pHead==NULL){ return NULL;}else{teacher *p=pHead;while(id!=p->id){p=p->pnext;if(p==NULL){ return NULL; }}return p;}}teacher * findLinkByName(char *name){if(pHead==NULL){return NULL;}else{teacher *p=pHead;while((strcmp(name,p->name))!=0){p=p->pnext;if(p==NULL){ return NULL;}}return p;}}teacher *findNodesByName(char *name,teacher *lista){teacher* listb;if (lista == NULL) return NULL;while(lista!=NULL){if(strcmp(name,lista->name)!=0){lista = lista->pnext;}else {listb = (teacher*)malloc(sizeof(teacher));listb->id=lista->id;strcpy(listb->name,lista->name);strcpy(listb->sex,lista->sex);strcpy(listb->workPlace,lista->workPlace);strcpy(listb->address,lista->address);strcpy(listb->tel,lista->tel);listb->salary=lista->salary;listb->benefit=lista->benefit;listb->livingAllowance=lista->livingAllowance;listb->shouldPay=lista->shouldPay;listb->telBill=lista->telBill;listb->waterBill=lista->waterBill;listb->rentPay=lista->rentPay;listb->incomeTax=lista->incomeTax;listb->cleanBill=lista->cleanBill;listb->fund=lista->fund;listb->totalDeduct=lista->totalDeduct;listb->realPay=lista->realPay;listb->pnext = findNodesByName(name,lista->pnext);return listb;}}}

(a)根据教师号查询教师信息

模块说明:

完成用户从界面输入要查询的教师号,在系统查询符合条件的教师信息链表,并在界面上显示的功能。

模块流程:

图 24– findLinkById()函数

对应函数:

find=findLinkById();if(find!=NULL){printf("==========================================\n");showNode(find);printf("==========================================\n");}else{printf("系统中没有找到此教师\n");}printf("--------按任意键回到菜单---------\n");getch();searchNodeByNameOrIdOrAll();break;

(b)根据教师姓名查询教师信息

模块说明:

完成用户从界面输入要查询的教师姓名,在系统查询符合条件的教师信息链表,并在界面上显示的功能。

模块流程:

图 25- findNodesByName()函数

对应函数:

printf("请输入教师姓名:");scanf("%s",&name);find = findNodesByName(name,copyLink(pHead));if(find!=NULL){printf("==========================================\n");if(link_length(find)==1){showLink(find);}else{showLinkByRow(find);}printf("==========================================\n");}else{printf("系统中没有找到此教师\n");}printf("--------按任意键回到菜单---------\n");getch();searchNodeByNameOrIdOrAll();break;

(c)按教师号顺序输出教师信息

模块说明:

用户从界面选择按行显示还是按列显示,按教师号从低到高显示全部教师信息的功能。

模块流程:

图 26- showLinkById()函数

对应函数:

void showLinkByRowOrCol(teacher *head){char ch;printf("请选择按行输出(1)or按列输出(2):\n");ch = getchar();fflush(stdin);switch(ch){case '1':showLinkByRow(head);break;case '2':showLink(head);break;case '0':exit(0);}}void showLink(teacher *head){teacher *p = head;while (p !=NULL){printf("教师号:%d\n姓名:%s\n性别:%s\n单位名称:%s\n家庭住址:%s\n联系电话:%s\n""基本工资:%.2f\n津贴: %.2f\n生活补贴:%.2f\n""应发工资:%.2f\n电话费: %.2f\n水电费: %.2f\n房租: %.2f\n所得税: %.2f\n""卫生费: %.2f\n公积金: %.2f\n合计扣款:%.2f\n实发工资:%.2f\n\n",p->id,p->name,p->sex,p->workPlace,p->address,p->tel,p->salary,p->benefit,p->livingAllowance,p->shouldPay,p->telBill,p->waterBill,p->rentPay,p->incomeTax,p->cleanBill,p->fund,p->totalDeduct,p->realPay);p = p->pnext;}}

(d)按工资(低->)输出教师信息

模块说明:

用户从界面输入按行显示还是按列显示,复制一个链表,利用递归排序的方式对链表进行按工资从低到高显示全部教师信息的功能。

模块流程:

图 27- showLinkByRealPay()函数

对应函数:

teacher* merge(teacher* list1,teacher* list2){teacher* newList = (teacher*)malloc(sizeof(teacher));teacher* nHead = newList;teacher* nTail = newList;newList->realPay = 0;newList->pnext = NULL;teacher* p = list1;teacher* q =list2;while(p!=NULL && q!=NULL){if(p->realPay realPay){nTail->pnext = p;nTail = p;p=p->pnext;}else{nTail->pnext = q;nTail = q;q=q->pnext;}}if(p!=NULL) nTail->pnext = p;if(q!=NULL) nTail->pnext = q;return nHead->pnext;}teacher* sortList(teacher* head){if(head==NULL) return head;if(head->pnext==NULL) return head;teacher* slow = head;teacher* fast = head;teacher* pre = NULL;while(fast->pnext!=NULL && fast->pnext->pnext!=NULL){pre=slow;slow=slow->pnext;fast=fast->pnext->pnext;}if(fast->pnext!=NULL){pre=slow;slow=slow->pnext;}teacher* mid = slow;pre->pnext = NULL;teacher* L1 =sortList(head);teacher* L2 =sortList(mid);return merge(L1,L2);}showLinkByRowOrCol(sortList(copyLink(pHead)));

【课设感想】

该程序的亮点是:

  1. 效率上:使用了链表存放教师数据,增删效率高。
  2. 数据安全性:把链表数据都存放到了txt文件里,程序编译第一件事就是读取文件,需要保存的数据全部放在了文件里,防止了数据丢失。
  3. 程序安全性:输入过程中对用户输入信息进行了校验,放置了数据格式错误导致的程序异常退出。
  4. 新功能:使用了归并排序,按教师工资从低到高的顺序对教师信息进行了输出,时间复杂度更低;使用冒泡排序对每次插入链表的教师信息按教师号排序。
  5. 除实现基本功能外排除的bug:
    1. 解决了链表中有重名时的删、改、查问题。进行删、改操作时,当姓名重复,原程序是找出一条就终止,后修改为找出重名信息并输出,再让用户通过教师号删、改。
    2. 解决了输入信息时的正确性校验。校验参数为,教师号(不重复),教师性别(男or女),电话号码(要求格式正确)

不足之处是:

  1. 函数复用率低。写的链表操作基本上就是只针对teacher类,很难搬到别的项目去。
  2. 界面美观度不够。因为是终端输出,界面全靠printf()。
  3. 复制了一个链表占用了空间资源。一开始设计程序时没思考到重名问题,因此链表操作均按教师号排序。但是按工资排序时,不复制链表会打乱顺序,如若设计时再多做一个按教师号排序的函数,就不需要这一步了。

【C程序源代码】

#include #include #include #define FILENAME "teacherMsg.txt"typedef struct Teacher{int id; char name[20];char sex[5];char workPlace[100];char address[100];char tel[20];float salary;float benefit;float livingAllowance;floatshouldPay;float telBill;float waterBill;float rentPay;floatincomeTax;float cleanBill;float fund;floattotalDeduct;float realPay;struct Teacher *pnext;} teacher;teacher * pHead = NULL;FILE *file;void menu();int check_number(int id);int check_tel(char *s);int check_sex(char *s); int link_length(teacher *head);void read_file();void link_save();void showLink(teacher *head);void showLinkByRow(teacher *head);void showNode(teacher *node);void showLinkByRowOrCol();void addNode();void deleteNodeByIdOrName();void deleteNode(teacher *node);void editNodeByIdOrName();void editNode(teacher *node);void searchNodeByNameOrIdOrAll();teacher* findLinkById();teacher* findLinkByName(char *name);teacher *findNodesByName(char *name,teacher *head);teacher* merge(teacher* list1,teacher* list2);teacher* sortList(teacher* head);teacher* copyLink(teacher* head);int main(){read_file();menu();}void menu(){system("cls");char ch;printf("***************教师工资管理系统***************\n");printf("-------------------菜单列表-------------------\n");printf("* 1:添加教师信息 *\n");printf("* 2.删除教师信息 *\n");printf("* 3:修改教师信息 *\n");printf("* 4:查询教师信息 *\n");printf("* 0.退出程序 *\n");printf("**********************************************\n");do{printf("请选择:");ch = getchar();fflush(stdin);switch(ch){case '1':addNode();break;case '2':deleteNodeByIdOrName();break;case '3':editNodeByIdOrName();break;case '4':searchNodeByNameOrIdOrAll();break;case '0':exit(0);}}while(ch!='0');}int check_number(int id){teacher *p; if(pHead==NULL){return 0;}else{p=pHead;while(p->id!=id){p=p->pnext;if(p==NULL)return 0;}printf("教师号已存在!\n");return 1;}}int check_tel(char *s){if(strlen(s) == 11&&s[0]=='1'&&((s[1]=='3') || (s[1]=='5') || (s[1]=='7') || (s[1]=='8'))){ return 0; }else{printf("手机号码不合法!\n"); return 1;}}int check_sex(char *s){if(strcmp(s,"男")==0||strcmp(s,"女")==0){ return 0; }else{printf("性别格式有误!\n"); return 1;}}int link_length(teacher *head){int length =0;teacher *n = head; while(NULL != n){++length;n = n->pnext;} return length;}void read_file(){file=fopen(FILENAME,"r+");if(file==NULL){file=fopen(FILENAME,"w");if(file==NULL)printf("\n\t文件创建失败!");}else{int k,len=0,c=0;while((k=fgetc(file))!=EOF){if(k=='\n'){if(c!=1)len++;}c++;}int id;char name[20];char sex[5];char workPlace[100];char address[100];char tel[20];float salary;float benefit;float livingAllowance;floatshouldPay;float telBill;float waterBill;float rentPay;floatincomeTax;float cleanBill;float fund;floattotalDeduct;float realPay;teacher *p=(teacher *)malloc(sizeof(teacher));rewind(file);int i; for(i=0;iid=id;strcpy(pn->name,name);strcpy(pn->sex,sex);strcpy(pn->workPlace,workPlace);strcpy(pn->address,address);strcpy(pn->tel,tel);pn->salary=salary;pn->benefit=benefit;pn->livingAllowance=livingAllowance;pn->shouldPay=shouldPay;pn->telBill=telBill;pn->waterBill=waterBill;pn->rentPay=rentPay;pn->incomeTax=incomeTax;pn->cleanBill=cleanBill;pn->fund=fund;pn->totalDeduct=totalDeduct;pn->realPay=realPay;pn->pnext=NULL;p->pnext=pn;p=pn;if(pHead==NULL){pHead=p;}}}fclose(file);}void link_save(){teacher *p = pHead;if ((file = fopen(FILENAME, "w")) == NULL){printf("文件创建失败!\n");exit(1);}while(p!=NULL){ fprintf(file,"%d %s %s %s %s %s %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",p->id,p->name,p->sex,p->workPlace,p->address,p->tel,p->salary,p->benefit,p->livingAllowance,p->shouldPay,p->telBill,p->waterBill,p->rentPay,p->incomeTax,p->cleanBill,p->fund,p->totalDeduct,p->realPay); p=p->pnext;}fclose(file);}void showLink(teacher *head){teacher *p = head;while (p !=NULL){printf("教师号:%d\n姓名:%s\n性别:%s\n单位名称:%s\n家庭住址:%s\n联系电话:%s\n""基本工资:%.2f\n津贴:%.2f\n生活补贴:%.2f\n""应发工资:%.2f\n电话费:%.2f\n水电费:%.2f\n房租:%.2f\n所得税:%.2f\n""卫生费:%.2f\n公积金:%.2f\n合计扣款:%.2f\n实发工资:%.2f\n\n",p->id,p->name,p->sex,p->workPlace,p->address,p->tel,p->salary,p->benefit,p->livingAllowance,p->shouldPay,p->telBill,p->waterBill,p->rentPay,p->incomeTax,p->cleanBill,p->fund,p->totalDeduct,p->realPay);p = p->pnext;}}void showLinkByRow(teacher *head){teacher *t = head;teacher *p = head;int i;for(i=0;iid,t->name,t->sex,t->workPlace,t->address,t->tel);t = t->pnext;}for(i=0;iid,p->name,p->salary,p->benefit,p->livingAllowance,p->shouldPay,p->telBill,p->waterBill,p->rentPay,p->incomeTax,p->cleanBill,p->fund,p->totalDeduct,p->realPay);p = p->pnext;}for(i=0;iid,node->name,node->sex,node->workPlace,node->address,node->tel,node->salary,node->benefit,node->livingAllowance,node->shouldPay,node->telBill,node->waterBill,node->rentPay,node->incomeTax,node->cleanBill,node->fund,node->totalDeduct,node->realPay);}void showLinkByRowOrCol(teacher *head){char ch;printf("请选择按行输出(1)or按列输出(2):\n");ch = getchar();fflush(stdin);switch(ch){case '1':showLinkByRow(head);break;case '2':showLink(head);break;case '0':exit(0);}}void addNode(){system("cls");teacher *pnew;char ch;pnew=(teacher *)malloc(sizeof(teacher));printf("请输入教师信息:\n");printf("==========================================\n");do{printf("请输入教师号:");scanf("%d",&pnew->id);}while(check_number(pnew->id));printf("请输入教师姓名:");scanf("%s",&pnew->name);do{printf("请输入教师性别:");scanf("%s",&pnew->sex);}while(check_sex(pnew->sex));printf("请输入教师单位名称:");scanf("%s",&pnew->workPlace);printf("请输入教师家庭住址:");scanf("%s",&pnew->address);do{printf("请输入教师的电话号码:");scanf("%s",&pnew->tel); }while(check_tel(pnew->tel));printf("==========================================\n");printf("请输入教师基本工资:");scanf("%f",&pnew->salary);printf("请输入教师的津贴:");scanf("%f",&pnew->benefit);printf("请输入教师的生活补贴:");scanf("%f",&pnew->livingAllowance);pnew->shouldPay=pnew->salary+pnew->benefit+pnew->livingAllowance;printf("==========应发工资为:%.2f=============\n",pnew->shouldPay); printf("请输入教师的电话费:");scanf("%f",&pnew->telBill);printf("请输入教师的水电费:");scanf("%f",&pnew->waterBill);printf("请输入教师的房租:");scanf("%f",&pnew->rentPay);printf("请输入教师的所得税:");scanf("%f",&pnew->incomeTax);printf("请输入教师的卫生费:");scanf("%f",&pnew->cleanBill);printf("请输入教师的公积金:");scanf("%f",&pnew->fund);pnew->totalDeduct=pnew->telBill+pnew->waterBill+pnew->rentPay+pnew->incomeTax+pnew->cleanBill+pnew->fund;printf("==========合计扣款为:%.2f=============\n",pnew->totalDeduct);pnew->realPay=pnew->shouldPay-pnew->totalDeduct;printf("==========实发工资为:%.2f=============\n",pnew->realPay);printf("==========================================\n");showNode(pnew);printf("==========================================\n");printf("确认录入该教师的信息吗(y/n):" />pnext=NULL;printf("录入成功!\n");link_save();printf("按任意键回到主菜单");getch();getchar();menu();return;}if(pHead->id>pnew->id){ teacher *pr=pHead; pHead=pnew; pHead->pnext=pr;}else{ teacher *p; teacher *bf; p=pHead; while(p->idid){bf=p;p=p->pnext;if(p==NULL){bf->pnext=pnew;pnew->pnext=NULL;printf("录入成功!\n");link_save();printf("\n-------按任意键回到主菜单--------");getch();getchar();menu();return;} }pnew->pnext=p;bf->pnext=pnew;}printf("录入成功!\n");link_save();printf("\n-------按任意键回到主菜单--------");getch();getchar();menu();}else{printf("确认录入该教师的信息吗(y/n):?\n");}} while(ch!='n'||ch!='y');}void deleteNode(teacher *node){char ch;printf("------------以下是要删除的教师信息------------\n");showNode(node);printf("----------------------------------------------\n");printf("确定删除该信息吗(y/n):?\n");do{ch = getch();if(ch == 'n'){printf("取消成功!\n");printf("--------按任意键回到菜单---------\n");getch();deleteNodeByIdOrName();return;}else if(ch =='y'){if(node->id==pHead->id){pHead=pHead->pnext;free(node);}else if(node->pnext==NULL){teacher *k;k=pHead;while(k->pnext!=node){k=k->pnext;}k->pnext=NULL;}else{teacher *d=pHead;while(d->pnext!=node){d=d->pnext;}d->pnext=node->pnext;}link_save();printf("---------删除成功!---------------\n");printf("--------按任意键回到菜单---------\n");getch();deleteNodeByIdOrName();return;}else{printf("确定删除该信息吗(y/n):?\n");}} while(ch!='n'||ch!='y');} void deleteNodeByIdOrName(){system("cls");char ch;printf("***************教师工资管理系统***************\n");printf("-----------------删除教师信息-----------------\n");printf("*1.根据教师号删除*\n");printf("*2.根据教师姓名删除*\n");printf("*3.回到主菜单*\n");printf("*0.退出程序*\n");printf("**********************************************\n");do{printf("请选择:");ch = getchar();fflush(stdin);switch(ch){teacher *find;teacher *nodes;char name[20]; case '1':find=findLinkById();if(find!=NULL){deleteNode(find);}else{printf("系统中没有找到此教师\n");printf("--------按任意键回到菜单---------\n");getch();deleteNodeByIdOrName();}break;case '2':printf("请输入教师姓名:");scanf("%s",&name);nodes=findNodesByName(name,copyLink(pHead));if(link_length(nodes)==1){find=findLinkByName(nodes->name);deleteNode(find);break;}else if(link_length(nodes)>1){printf("有教师重名,删除失败!\n重名结果如下:\n");printf("==========================================\n");showLinkByRow(nodes);printf("==========================================\n");printf("\n提示:请根据教师号删除\n\n");printf("--------按任意键回到菜单---------\n");getch();deleteNodeByIdOrName();break;break;}else{printf("系统中没有找到此教师\n");printf("--------按任意键回到菜单---------\n");getch();deleteNodeByIdOrName();break;}case '3':menu();break; case '0':exit(0);break;}}while(ch!='0');}void editNode(teacher *node){char ch;printf("------------以下是要修改的教师信息------------\n");showNode(node);printf("----------------------------------------------\n");printf("确定修改该信息吗(y/n):?\n");do{ch = getch();if(ch == 'n'){printf("取消成功!\n");printf("--------按任意键回到菜单---------\n");getch();editNodeByIdOrName();return;}else if(ch =='y'){printf("请重新输入以下信息:\n");printf("==========================================\n");printf("请输入教师姓名:");scanf("%s",&node->name);printf("请输入教师性别:");scanf("%s",&node->sex);printf("请输入教师单位名称:");scanf("%s",&node->workPlace);printf("请输入教师家庭住址:");scanf("%s",&node->address);printf("请输入教师的电话号码:");scanf("%s",&node->tel); printf("==========================================\n");printf("请输入教师基本工资:");scanf("%f",&node->salary);printf("请输入教师的津贴:");scanf("%f",&node->benefit);printf("请输入教师的生活补贴:");scanf("%f",&node->livingAllowance);node->shouldPay=node->salary+node->benefit+node->livingAllowance;printf("==========应发工资为:%.2f=============\n",node->shouldPay); printf("请输入教师的电话费:");scanf("%f",&node->telBill);printf("请输入教师的水电费:");scanf("%f",&node->waterBill);printf("请输入教师的房租:");scanf("%f",&node->rentPay);printf("请输入教师的所得税:");scanf("%f",&node->incomeTax);printf("请输入教师的卫生费:");scanf("%f",&node->cleanBill);printf("请输入教师的公积金:");scanf("%f",&node->fund);node->totalDeduct=node->telBill+node->waterBill+node->rentPay+node->incomeTax+node->cleanBill+node->fund;printf("==========合计扣款为:%.2f=============\n",node->totalDeduct);node->realPay=node->shouldPay-node->totalDeduct;printf("==========实发工资为:%.2f=============\n",node->realPay);printf("==========================================\n");link_save();printf("---------修改成功!---------------\n");printf("--------按任意键回到菜单---------\n");getch();editNodeByIdOrName();return;}else{printf("确定修改该信息吗(y/n):?\n");}} while(ch!='n'||ch!='y'); }void editNodeByIdOrName(){system("cls");char ch;printf("***************教师工资管理系统***************\n");printf("----------------修改教师信息-----------------\n");printf("*1.根据教师号修改*\n");printf("*2.根据教师姓名修改*\n");printf("*3.回到主菜单*\n");printf("*0.退出程序*\n");printf("**********************************************\n");do{printf("请选择:");ch = getchar();fflush(stdin);switch(ch){teacher *find;teacher *nodes;char name[20];case '1':find=findLinkById();if(find!=NULL){editNode(find);}else{printf("系统中没有找到此教师\n");printf("--------按任意键回到菜单---------\n");getch();editNodeByIdOrName();}break;case '2':printf("请输入教师姓名:");scanf("%s",&name);nodes=findNodesByName(name,copyLink(pHead));if(link_length(nodes)==1){find=findLinkByName(nodes->name);editNode(find);break;}else if(link_length(nodes)>1){printf("有教师重名,修改失败!\n重名结果如下:\n");printf("==========================================\n");showLinkByRow(nodes);printf("==========================================\n");printf("\n提示:请根据教师号修改\n\n");printf("--------按任意键回到菜单---------\n");getch();editNodeByIdOrName();break;}else{printf("系统中没有找到此教师\n");printf("--------按任意键回到菜单---------\n");getch();editNodeByIdOrName();break;}case '3':menu();break; case '0':exit(0);break;}}while(ch!='0');}void searchNodeByNameOrIdOrAll(){system("cls");char ch;printf("***************教师工资管理系统***************\n");printf("-----------------查询教师信息-----------------\n");printf("*1.根据教师号查询*\n");printf("*2.根据教师姓名查询*\n");printf("*3.按教师号显示教师信息*\n");printf("*4.按工资(低->高)显示教师信息*\n");printf("*5.回到主菜单*\n");printf("*0.退出程序*\n");printf("**********************************************\n");do{printf("请选择:");ch = getchar();fflush(stdin);switch(ch){teacher *find;char name[20];case '1':find=findLinkById();if(find!=NULL){printf("==========================================\n");showNode(find);printf("==========================================\n");}else{printf("系统中没有找到此教师\n");}printf("--------按任意键回到菜单---------\n");getch();searchNodeByNameOrIdOrAll();break;case '2':printf("请输入教师姓名:");scanf("%s",&name);find = findNodesByName(name,copyLink(pHead));if(find!=NULL){printf("==========================================\n");if(link_length(find)==1){showLink(find);}else{showLinkByRow(find);}printf("==========================================\n");}else{printf("系统中没有找到此教师\n");} printf("--------按任意键回到菜单---------\n");getch();searchNodeByNameOrIdOrAll();break;case '3':showLinkByRowOrCol(pHead);printf("--------按任意键回到菜单---------\n");getch();searchNodeByNameOrIdOrAll();break;case '4':showLinkByRowOrCol(sortList(copyLink(pHead)));printf("--------按任意键回到菜单---------\n");getch();searchNodeByNameOrIdOrAll();break;case '5':menu();break; case '6':exit(0);break;}}while(ch!='0');}teacher * findLinkById(){int id; printf("请输入教师号:");scanf("%d",&id);if(pHead==NULL){return NULL;}else{teacher *p=pHead;while(id!=p->id){p=p->pnext;if(p==NULL){return NULL;}}return p;}}teacher * findLinkByName(char *name){if(pHead==NULL){return NULL;}else{teacher *p=pHead;while((strcmp(name,p->name))!=0){p=p->pnext;if(p==NULL){return NULL;}}return p;}}teacher *findNodesByName(char *name,teacher *lista){teacher* listb;if (lista == NULL) return NULL;while(lista!=NULL){if(strcmp(name,lista->name)!=0){lista = lista->pnext;}else {listb = (teacher*)malloc(sizeof(teacher));listb->id=lista->id;strcpy(listb->name,lista->name);strcpy(listb->sex,lista->sex);strcpy(listb->workPlace,lista->workPlace);strcpy(listb->address,lista->address);strcpy(listb->tel,lista->tel);listb->salary=lista->salary;listb->benefit=lista->benefit;listb->livingAllowance=lista->livingAllowance;listb->shouldPay=lista->shouldPay;listb->telBill=lista->telBill;listb->waterBill=lista->waterBill;listb->rentPay=lista->rentPay;listb->incomeTax=lista->incomeTax;listb->cleanBill=lista->cleanBill;listb->fund=lista->fund;listb->totalDeduct=lista->totalDeduct;listb->realPay=lista->realPay;listb->pnext = findNodesByName(name,lista->pnext);return listb;}}}teacher* merge(teacher* list1,teacher* list2){teacher* newList = (teacher*)malloc(sizeof(teacher));teacher* nHead = newList;teacher* nTail = newList;newList->realPay = 0;newList->pnext = NULL;teacher* p = list1;teacher* q =list2;while(p!=NULL && q!=NULL){if(p->realPay realPay){nTail->pnext = p;nTail = p;p=p->pnext;}else{nTail->pnext = q;nTail = q;q=q->pnext;}}if(p!=NULL) nTail->pnext = p;if(q!=NULL) nTail->pnext = q;return nHead->pnext;}teacher* sortList(teacher* head){if(head==NULL) return head;if(head->pnext==NULL) return head;teacher* slow = head;teacher* fast = head;teacher* pre = NULL;while(fast->pnext!=NULL && fast->pnext->pnext!=NULL){pre=slow;slow=slow->pnext;fast=fast->pnext->pnext;}if(fast->pnext!=NULL){pre=slow;slow=slow->pnext;}teacher* mid = slow;pre->pnext = NULL;teacher* L1 =sortList(head);teacher* L2 =sortList(mid);return merge(L1,L2);}teacher* copyLink(teacher* lista){teacher* listb;if (lista == NULL){return NULL;}else {listb = (teacher*)malloc(sizeof(teacher));listb->id=lista->id;strcpy(listb->name,lista->name);strcpy(listb->sex,lista->sex);strcpy(listb->workPlace,lista->workPlace);strcpy(listb->address,lista->address);strcpy(listb->tel,lista->tel);listb->salary=lista->salary;listb->benefit=lista->benefit;listb->livingAllowance=lista->livingAllowance;listb->shouldPay=lista->shouldPay;listb->telBill=lista->telBill;listb->waterBill=lista->waterBill;listb->rentPay=lista->rentPay;listb->incomeTax=lista->incomeTax;listb->cleanBill=lista->cleanBill;listb->fund=lista->fund;listb->totalDeduct=lista->totalDeduct;listb->realPay=lista->realPay;listb->pnext = copyLink(lista->pnext);return listb;}}