成都信息工程学院计算机系
课程实验报告
实验课程: C语言程序设计2 实验项目: 职工管理系统 指导教师: 李莉丽 学生姓名: 桂柯 学生学号: 2010051102 班 级: 计科3班 实验地点: 5201 实验时间: 2011 年 5月 11日 点~ 点 实验成绩: 评阅老师: 李莉丽 (说明:实验报告必须包含下面的每项内容,根据实验情况认真填写,封面必须打印或复印(A4纸),书写上机实验报告内容的纸张也用A4纸,最后从侧面装订)
一【上机实验目的】
通过亲自设计程序,可以令我们熟悉c语言操作,更熟练的掌握c语句。初步体会编程的过程,为将来的程序深入学习打下基础和培养兴趣。
二【实验环境】 TC2.0
三【上机实验内容】
职工信息管理系统 要求:
职工信息包括职工号,姓名,性别,年龄,学历,工资,住址,电话等(职工号不相等)。试设计一职工信息管理系统,使之能够提供下列功能: (1)系统以菜单方式工作
(2)职工信息录入功能(职工信息用文件保存) (3)职工信息浏览功能
(4)职工信息查询功能,查询方式: 1)按学历查询 2)按职工号查询
(5)职工信息删除,修改功能(可选项)。
思路:
(1)录入并向文件里保存数据的实现思路:C语言并没有提供由键盘输入数据直接录入文件的功能,只有内存变量向文件写入数据的功能,而由键盘输入数据可以到内存变量,因此实现此部分功能时,应当由键盘将数据放入变量,再由变量写入文件。这里录入要求不采用书上例子,它是用结构体数组,我们要求只用一个结构体实现。先将一个人的信息放入结构体,将这个结构体数据写入文件后,再将下一个人的信息继续放在这个结构体中,再将这个结构体写入文件。这样节省内存空间。
计算并修改文件里数据的实现思路:这部分的功能的实现应当先将文件的数据读到变量当中,在变量当中完成计算,再将数据写入文件。如果只是修改文件的数据,并不计算,则可以直接定位到文件中相应的位置,写入数据,则把原来的数据覆盖以完成修改。
(2)向文件里追加数据的实现思路:文件本身提供了这项功能,只要以 “a”的方式打开就行。然后向文件写入的数据,直接放在文件末尾。
(3)查找文件里是否有某项数据的实现思路:C语言并没有提供判断文件内容的功能,必须将文件内容读到变量里再进行判断。实际的查找可能是在大量的数据里的查找,高效的查找是折半查找(下学期的数据结构专门讲这一内容),折半的前提是排序,因此需先对排序后的文件读出,以折半方式查找。(这要要求,是希望巩固折半查找与排序两个重要算法,至于它的时空效率是否高,可以学完《数据结构》知识后自己再判断)。
(4)根据要求显示文件里的某些数据或全部数据的实现思路:C语言没有提供将文件内容显示的功能,所以需要将文件内容读到变量里,再显示变量。
(5)在文件里插入或删除某项数据的实现思路:C语言同样没有直接提供该项功能,因此必须借由内存变量完成。由以前的知识知道,在大量的数据里删除一个数,用数组表示不合适,因为涉及到大量的数据的移动,用链表是合适的,效率高(关于这一点,在《数据结构》这门课有详细的讲解)。因此完成这部分操作要求用链表实现,先将文件里的数据读出组织成链表,在链表上完成插入与删除后,再将链表中的数据写入文件。
(6)按某个数据项进行排序生成排序文件的实现思路:排序是在数组里实现。因此先要将文件里的数据读到数组里,将数组排完序后,再将数据写入文件(一般写入一个新文件)。
四【上机调试程序流程图】
1.显示主菜单(以如下程序作为介绍)
2.添加职工信息
3.浏览职工信息。
4.查询职工信息。
4(1)根据标号查询职工信息。
(2)根据姓名查询职工信息。
(3)根据年龄查询职工信息。
5.修改职工信息。
浏览修改后的职工信息。
6.删除职工信息。
浏览删除后的职工信息。
7.用链表添加职工信息。
浏览添加后的职工信息。
五【上机调试中出现的错误信息、错误原因及解决办法】
1.光条菜单的错误:刚开始只能用键盘上的英文字母控制光条上下移动,想用上下箭头的ASCII代码,结果错误不能上下移动 解决方法:使用键盘扫描码。
2、浏览函数 scan()在调试和链接的时候都没有出现错误提示,但在运行的时候出现了问题。写入指定位置的文件,打开后总会有乱码。与c语言课本上的例题对照后发现,我写的fopen(\没有指定文件的存储类型。 解决方法:在文件名wenjian后面加上.txt后即可。
3.浏览函数scan()遇到的问题虽然不大,但解决起来很麻烦。理想的运行结果是美观整齐。即下面的职工信息分别与第一个printf输出的中文项目提示对齐。 解决方法:不断修改空格个数,不断运行察看效果。 4.程序运行后菜单界面不消失
解决方法:使用清屏函数,是每次运行后界面还原。 5.功能函数运行完后会跳出界面,直接退出。 解决方法:在每个功能函数的后面加如返回值。
六【上机调试后的源程序及还存在的问题】
源程序:
#include
#define ESC 0x1b #define ENTER 0x0d #define UP 0x48 #define DOWN 0x50 #define LEFT 0x4b #define RIGHT 0x4d
typedef struct { int No; int age; char name[20]; }WORKERBASIC;
typedef struct worker { WORKERBASIC workerinfo; struct worker *next; }WORKER;
void cleanscreen() { int i,j; gotoxy(1,1); textbackground(RED); for(i=1;i<=25;i++) for(j=1;j<=80;j++) cprintf(\ clrscr(); }
void Initial() { int i,j; char list[7][20]={\ \ \
/*键盘扫描码*/
/*定义存放职工信息的类型*/
/*清屏*/
/*定义初始化程序的函数*/
/*菜单名*/
\ \ \ \ cleanscreen(); textbackground(YELLOW); for(i=1;i<=14;i++) /*画窗口*/ { for(j=1;j<=80;j++) { if (i==1||i==14||j<=2||(j>=79)) cprintf(\ else if (i>=3&&i<=12&&j>=5&&j<=76) cprintf(\ else printf(\ } } gotoxy(32,4); textcolor(BLACK); cprintf(\ gotoxy(31,14); cprintf(\ System -- BY GK\ for(i=0;i<7;i++) /*显示菜单*/ { gotoxy(34,i+6); cprintf(\ } }
void PrintPause() /*暂停*/ { printf(\ getch(); }
void Guangtiao(int flag) /*定义画光条的函数*/ { char list[7][20]={\ \ \
\ \ \ \ gotoxy(34,flag+5); textcolor(WHITE); textbackground(BLACK); cprintf(\ textcolor(LIGHTGRAY); }
int Add() /*添加信息*/ { WORKERBASIC new; FILE *fp=NULL; char ch='y'; while(ch=='y') { cleanscreen(); printf(\ scanf(\ getchar(); printf(\ scanf(\ getchar(); printf(\ scanf(\ getchar(); if((fp=fopen(\ { fp=fopen(\ } if(fwrite(&new,sizeof(WORKERBASIC),1,fp)!=1) { printf(\ PrintPause(); } fclose(fp); printf(\ scanf(\ } return 0; }
int Scan() /*查看信息*/ { WORKERBASIC load; FILE *fp=NULL; int n=0; cleanscreen(); if((fp=fopen(\ { printf(\ PrintPause(); return 0; } printf(\ printf(\ while(!feof(fp)) { if (fread(&load,sizeof(WORKERBASIC),1,fp)==1) n++; else break; printf(\ } printf(\ printf(\ fclose(fp); PrintPause(); return 0; }
void exchange(WORKERBASIC *max,WORKERBASIC *min) 职工在数组中的位置*/ { WORKERBASIC t; strcpy(t.name,max->name); t.No=max->No; strcpy(max->name,min->name); max->No=min->No; strcpy(min->name,t.name);
/*调换两个
min->No=t.No; }
int EditByNo(WORKERBASIC *F1,int n) /*按编号查找*/ { int i,j,k,num,high,low,mid,flag=0; for(i=0;i
low=mid+1; else if (num<((F1+mid*sizeof(WORKERBASIC))->No)) high=mid-1; else if (num==((F1+mid*sizeof(WORKERBASIC))->No)) flag=1; } if (flag==0) { printf(\ } else { printf(\ printf(\ printf(\ERBASIC))->age, (F1+mid*sizeof(WORKERBASIC))->name); printf(\ } PrintPause(); return 0; }
int EditByName(WORKERBASIC *F1,int n) /*按姓名查找*/ { char str[20]; int i,j,k,flag=0,low,high,mid; for(i=0;i
if (k!=i) exchange((F1+i*sizeof(WORKERBASIC)),(F1+k*sizeof(WORKERBASIC))); } /*此显示信息只为说明职工已按名字排序,该部分可删除*/ printf(\ printf(\ for(i=0;i
} PrintPause(); return 0; }
int EditByage(WORKERBASIC *F1,int n) /*按年龄查找*/ { int a,flag=0,i; printf(\ printf(\ for(i=0;i
return 0; }
int Edit() /*查找*/ { WORKERBASIC load,*F1; int n=0,key=0,i; FILE *fp=NULL; cleanscreen(); if ((fp=fopen(\ { printf(\ PrintPause(); return 0; } while(!feof(fp)) /*统计职工的数量*/ { if (fread(&load,sizeof(WORKERBASIC),1,fp)==1) n++; } fclose(fp); if (n==0) { printf(\ PrintPause(); return 0; } F1=(WORKERBASIC *)malloc(n*sizeof(WORKERBASIC)); /*按职工的人数申请内存空间*/ fp=fopen(\ for(i=0;i } fclose(fp); while(key!=ESC) { clrscr(); printf(\ printf(\ printf(\ printf(\ printf(\ printf(\ printf(\ printf(\ or Esc?\\n\ key=getch(); switch(key) { case '1': key=EditByNo(F1,n); break; case '2': key=EditByName(F1,n); break; case '3': key=EditByage(F1,n); break; } } free(F1); return 0; } int Modify() { WORKER *head=NULL,*t=NULL,*load=NULL; FILE *fp=NULL; char str[20]; int num; cleanscreen(); load=(WORKER *)malloc(sizeof(WORKER)); if((fp=fopen(\ { /*修改*/ printf(\ PrintPause(); return 0; } head=t=load; if (fread(load,sizeof(WORKERBASIC),1,fp)!=1) { printf(\ PrintPause(); return 0; } while(!feof(fp)) { load=(WORKER *)malloc(sizeof(WORKER)); t->next=load; if (fread(load,sizeof(WORKERBASIC),1,fp)!=1) break; t=load; } t->next=NULL;/*创建链表完成*/ fclose(fp); t=head; Scan(); printf(\ printf(\ scanf(\ getchar(); num=atoi(str); /*把字符串转换为长整型数*/ if ((strcmp(t->workerinfo.name,str)==0)||(num==t->workerinfo.No)||(num==t->workerinfo.age)) { printf(\ scanf(\ getchar(); printf(\ scanf(\ getchar(); printf(\ scanf(\ getchar(); printf(\ fp=fopen(\ t=head; if (head!=NULL) { fwrite(t,sizeof(WORKERBASIC),1,fp); while(t->next!=NULL) { t=t->next; if(fwrite(t,sizeof(WORKERBASIC),1,fp)!=1) { printf(\ PrintPause(); break; } } free(head); fclose(fp); } PrintPause(); return 0; } /*存入文件(目标在首地址)*/ while(t->next!=NULL) { t=t->next; if ((strcmp(t->workerinfo.name,str)==0)||(num==t->workerinfo.No)||(num==t->workerinfo.age)) { printf(\ scanf(\ getchar(); printf(\ scanf(\ getchar(); printf(\ scanf(\ getchar(); printf(\ fp=fopen(\ t=head; if (head!=NULL) { fwrite(t,sizeof(WORKERBASIC),1,fp); while(t->next!=NULL) { t=t->next; return 0; b->next=t->next; t->next=a; a->next=b->next; printf(\ fp=fopen(\ t=head; if (head!=NULL) { fwrite(t,sizeof(WORKERBASIC),1,fp); while(t->next!=NULL) { t=t->next; if(fwrite(t,sizeof(WORKERBASIC),1,fp)!=1) { printf(\ PrintPause(); break; } } } free(head); fclose(fp); PrintPause(); return 0; } } printf(\ PrintPause(); return 0; } int Slecting(int flag) /*选择功能*/ { switch(flag) { case 1: return Add(); case 2: return Scan(); case 3: return Edit(); case 4: return Modify(); case 5: return Delete(); case 6: return Into(); case 7: return 1; default: return 0; } } int main() { int flag=1,key,esc=0,i,j; while(!esc) { Initial(); /*画程序界面*/ Guangtiao(flag); /*画光条*/ key=getch(); /*等待键盘输入*/ if (key>=0x31&&key<=0x36) /*可以按数字键选择菜单*/ { flag = key-0x30; esc=Slecting(flag); } switch(key) /*匹配按键 执行功能*/ { case UP: /*光标上移*/ flag--; if (flag<1) flag=7; /*光标回跳*/ break; case DOWN: flag++; /*光标下移*/ if (flag>7) /*光标回跳*/ flag=1; break; case ENTER: /*确认功能*/ esc=Slecting(flag); break; } } return 0; } ?? 一个大的问题就是每次当用链表将数据存入文件当中时,无法将内存当中的链表释放,这是老师给我提出的问题,我也觉的是个很大的问题。 七【上机实验中的其他它问题及心得】 经过一学期的C语言学习,我们掌握了C语言的基础知识,能够读懂别人用c语言设计的程序。平时的程序设计大多是以填空的形式出现,虽然有所接触,但都不完全。而这两周的课程设计,却让我们完完全全用自己学到的知识编写一个完整的体统程序。这是一个新的挑战,也是一种新的学习。 我选择的是备选题目中的——职工信息管理系统。这需要我自己设计一个系统,可以输入信息,保存到文件里,再从文件里调出来,使之显示在屏幕上,进行删除、添加(并且这两项功能要用链表完成)等对信息的修改。初看到这个题目觉得很简单,但当我做到电脑前准备开始编写代码的时候才发现无从下手。通过去图书馆查找程序设计相关的书籍,和上网参考前人编写的类似程序,我脑中才有了一个大概方向。 首先的就是老师要求的必须使用光条菜单,但自己完全没有光条菜单的概念,我花费了很多时间在百度搜索,一直没有找到理想的光条菜单。直到有同学做出来了,我就去询问,这才了解了做光条菜单的基本要求和方法,然后在我认真搞懂了光条函数的原理之后,我就开始根据自己程序的要求制作光条菜单,把自己程序的功能完全用光条菜单显示出来。经过自己的努力,最终还是把光条菜单做出来了。但当时做出来的仅仅只能够用键盘上的上下左右健来控制,我的想法就是也可以根据系统的功能选项,制作出能够利用键盘上的数字健也能够控制自己的功能选项,这样就能够让自己的程序更具有操作性,然后根据查资料可以了解到可以用0x数来表示键盘上的数字健,然后就多加了一个可以用数字健来控制功能的方法。 然后自己就开始编写录入功能的程序,我采用的是一个功能一个程序的方法,这样就能够更好的检查自己的程序,以防出错,开始编写录入功能的时候,存入文件当时还不是很了解,然后就翻了书,查了资料,问了同学这才知道怎样讲录入的信息存入文件,而且打开文件的方式也会根据自己的功能而不同,这也是当时难住我的地方,接着就是浏览功能,这里到没有多大的问题,只是美观上下了点功夫,调了很久,然后就是最让自己为难的链表,大概是因为自己的链表没有学的怎么好,所以自己都没有多大的底气,幸好我室友帮我认真讲解了一下链表,然后听过自己对书上知识的了解,和寝室室友的共同编写下,这才用链表把添加和删除的功能编写好,在这里,我和我室友都是编写的职工管理系统,所以我们经常讨论这其中存在的问题,但最后我们两个通过各自的努力用链表把这两个重要的功能编写好了。在编写这两个功能的过程中,我深刻的明白了为什么老师要求我们用链表来编写程序了,因为链表对于这个程序来说显得更加的高效,让程序运行的速度更加快,这样就能够省去更多的时间,让这个系统更加的有效率。也明白了在以后工作的时候,编程当中方法的选择也会对自己程序的效率产生很大的影响。最后遇到的就是对职工的查询功能,这里我选择可以运用两种方式进行选择查询,但这其中就是根据姓名和职工号的查询,这里就是字符串和数字两种不同类型的查询方法。而且老师要求的方法是必须使用折半查找方法,这样我就只有下去对折半查找方法进行了研究,也让自己费了点劲。还有就是当时的程序每次运行是都会显示出上次程序运行的痕迹,最后问了同学才知道要添加一个清屏函数,这样就会让自己的程序看着很清楚,不会那么的模糊不清。 到了我把几个最重要的功能都编写成功之后,我遇到的最大的麻烦就是怎么样将这些功能都整合到运用光条菜单控制当中,最后终于功夫不负有心人,我最终把这些功能整合到了一起,通过自己的不断调试,最终做成了这个职工管理系统。但最后的答辩自己还是有点紧张,而且老师也指出了我程序当中存在的问题,而最大的问题就是每次当用链表将数据存入文件当中时,无法将内存当中的链表释放,这是个大的问题,我在后面的时间中,也将针对这些问题,对程序进行改进。 总之,经过这一次的课程设计,我们体会到了痛苦与快乐同存的感觉。当最后一次成功串联运行所有函数时,真的很开心。通过这次实践,我们能够更熟练掌握C语言,特别是循环和文件和链表,当时在课堂上没有学太清楚的,这个程序设计之后都很明白了。同时增加了我们对程序设计的兴趣,暑假回家我还会尝试着做一些其他的小系统。