




已阅读5页,还剩68页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
课 程 实 验 报 告课程名称: C语言课程设计实验 专业班级:学 号:姓 名:指导教师:报告日期:计算机科学与技术学院1系统需求分析1.1系统名称楼盘查询系统1.2主要内容建立楼盘信息系统,提供创建、编辑和综合查询等基本业务管理和服务。系统主要提供武汉城市楼盘的快速查询、检索和统计。具有,按城区、按户型和按价格等查询和统计信息,并以适当的形式输出给用户。系统主要涉及“楼盘”、“楼栋”和“房屋”3类信息。 “楼盘”信息由楼盘编号、楼盘名称、楼盘地址、开发商和物业公司等数据项目组成,“楼栋”信息是由楼栋编号、单元和楼层等数据项组成,“房屋”信息由房屋编号、户型、面积、公摊率和价格等数据项目组成。在磁盘上,采用3个文件分别存储“楼盘”、“楼栋”和“房屋”的数据。“楼栋”信息中增加楼盘编号,“房屋”信息中增加楼盘编号和楼栋编号。在内存中,采用如下图所示链式数据结构。 head 楼栋11 楼栋12 楼栋1m 楼盘1 楼盘2楼盘n 房屋111 房屋11p 楼盘查询系统的链表结构示意图2数据信息项&程序框架2.1房屋数据项其中房屋结构体中加入指向下一房屋结点的指针。相关程序代码:typedef struct house_node char estate_id10; /*楼盘编号*/char build_id10; /*楼栋编号*/char house_id10; /*房屋编号*/char type20; /*户型*/int area; /*房屋面积*/float shared_rate; /*公摊率*/int one_price;/*单位面积价格*/struct house_node*next; /*指向下一个房屋结点*/HOUSE_NODE;2.2楼栋数据项其中楼栋结构体中加入指向下一个楼栋结点的指针和指向房屋的指针。相关程序代码:typedef struct build_node char estate_id10; /*楼盘编号*/char build_id10; /*楼栋编号*/int unit; /*楼栋所含单元数*/int floor; /*楼层*/struct house_node*hnext; /*指向下一个房屋结点*/struct build_node*next; /*指向下一个楼栋结点*/BUILD_NODE;2.3楼盘数据项其中楼盘结构体中加入指向下一个楼盘结点的指针和楼栋结点的指针。相关程序代码:typedef struct estate_node char estate_id10; /*楼盘编号*/char name20; /*楼盘名称*/char city10; /*所在城区*/char address30; /*楼盘地址*/char developer20; /*开发商*/char management_company20; /*物业公司*/struct build_node*bnext; /*指向下一个楼栋结点*/struct estate_node*next; /*指向下一个楼盘结点*/ESTATE_NODE;2.4文件存储我们将数据文件用二进制的形式存储在estate.dat, build.dat和 house.dat文件中,并放在程序当前目录。2.5程序框架结构程序主要框架可以分为两个部分,一部分是文本菜单界面的设计和用户的交互界面,另一方面是程序处理数据等的功能实现,两方面的着重点不同,但在程序的设计中却是相辅相成的。3功能函数3.1文本菜单界面设计函数该程序采用控制台文本菜单界面,运用基本的控制台win api函数完成控制台界面,以设置热区、缓冲区、菜单窗口等等,在此不做赘述。特别的,我们可以利用事先封装好的程序段实现很多功能。初始化后的主菜单界面如下以下重点介绍其他功能函数3.2加载数据函数利用加载数据函数把.dat文件中的数据加载到内存中来,建立如下十字链表结构。 head 楼栋11 楼栋12 楼栋1m 楼盘1 楼盘2楼盘n 房屋111 房屋11p 其中链表的建立均运用后进先出的方式。3.2.1流程设计从楼盘到楼栋到房屋链表的逐步建立流程如下:其中LoadData函数调用CreatList函数,3.2.2函数代码函数实现代码如下:BOOL LoadData()int Re;Re = CreatList(&hd);if (Rebnext = NULL;pEstateNode-next = hd;hd = pEstateNode;pEstateNode = (ESTATE_NODE*)malloc(sizeof(ESTATE_NODE);fread(pEstateNode, sizeof(ESTATE_NODE), 1, pFile);free(pEstateNode);fclose(pFile);if (hd = NULL)printf(楼盘信息数据文件加载失败!n);return num;printf(楼盘信息数据文件加载成功!n);*phead = hd;num+;if (pFile = fopen(gp_build_info_filename, rb) = NULL)printf(楼栋信息数据文件打开失败!n);return num;printf(楼栋信息数据文件打开成功!n);num+;/*从数据文件中读取楼栋信息数据存入主链对应结点的学生基本信息支链中*/pBuildNode = (BUILD_NODE*)malloc(sizeof(BUILD_NODE);fread(pBuildNode, sizeof(BUILD_NODE), 1, pFile);while (!feof(pFile)pBuildNode-hnext = NULL;/*在主链上查找楼栋对应的楼盘主链结点*/pEstateNode = hd;while (pEstateNode != NULL&strcmp(pEstateNode-estate_id, pBuildNode-estate_id) != 0)pEstateNode = pEstateNode-next;/*如果找到,则将结点以后进先出方式插入楼栋信息支链*/if (pEstateNode != NULL)pBuildNode-next = pEstateNode-bnext;pEstateNode-bnext = pBuildNode;else /*如果未找到,则释放所创建结点的内存空间*/free(pBuildNode);pBuildNode = (BUILD_NODE*)malloc(sizeof(BUILD_NODE);fread(pBuildNode, sizeof(BUILD_NODE), 1, pFile);free(pBuildNode);fclose(pFile);if (pFile = fopen(gp_house_info_filename, rb) = NULL)printf(房屋信息数据文件打开失败!n);return num;printf(房屋信息数据文件打开成功!n);num+;/*从数据文件中读取房屋信息数据存入楼栋信息对应结点的房屋信息支链中*/pHouseNode = (HOUSE_NODE*)malloc(sizeof(HOUSE_NODE);fread(pHouseNode, sizeof(HOUSE_NODE), 1, pFile);while (!feof(pFile)/*在楼栋支链上查找该房屋所在楼栋对应的结点*/pEstateNode = hd;find = 0;while (pEstateNode != NULL&find = 0)if (strcmp(pEstateNode-estate_id, pHouseNode-estate_id) = 0)pBuildNode = pEstateNode-bnext;while (pBuildNode != NULL&find = 0)if (strcmp(pBuildNode-build_id, pHouseNode-build_id) = 0)find = 1;break;pBuildNode = pBuildNode-next;pEstateNode = pEstateNode-next;if (find) /*如果找到则将结点以后进先出方式插入房屋信息支链中*/pHouseNode-next = pBuildNode-hnext;pBuildNode-hnext = pHouseNode;else /*如果未找到,则释放所创建结点的内存空间*/free(pHouseNode);pHouseNode = (HOUSE_NODE*)malloc(sizeof(HOUSE_NODE);fread(pHouseNode, sizeof(HOUSE_NODE), 1, pFile);free(pHouseNode);fclose(pFile);return num;LoadData函数如果返回TRUE(宏为1),则代表所有数据文件加载成功;若返回FALSE(宏为0),则代表有文件加载失败。3.2.3相关截图1)打开文件失败2)打开成功却加载失败3)打开并加载成功后自动跳转到主菜单界面3.3管理员账号密码函数(Administrator()注意到我们的系统不仅面向用户,而且还面向管理员,只有管理员才有修改其文件数据的权利,为了将两者区别开来,做了一个简易的管理员账号密码函数,通过该验证便可获得管理员的权限对数据进行修改。3.3.1流程设计我们对需要管理员权利的项限定在数据维护方面,即数据的添加、删除和修改皆要通过管理员验证才能够进行,于是我们可以用一个特征变量来表示用户是否通过了管理员验证,具体的,在该程序中我们用的是pass,一个int类型的变量,当该变量被赋值为0时表示通过验证,可进行后续操作,否则,不能进行后续操作。对于密码验证函数Administrator我们如下设计,并达到几个方面的效果。1. 对账号和密码的输入进行了字数限制,即当输入超出限制的时候,多余部分不予显示,将其丢弃,以账号输入为例。2. 对于密码的输入,回显应该为*,对以上流程略作修改即可3. 登陆成功则进行提示下一步操作;登陆失败则给予用户两个选择,要么继续输入账号和密码,要么返回主菜单。3.3.2函数代码/* 函数名称:Adminstrator* 函数功能:获取管理员权限* 输入参数:无* 输出参数:pass* 返回值:无* 函数说明:*/void Administrator(void)char account21;char password21;int deal1=1;while (pass & deal1)int i = 0;/ i代表光标当前的位置char c;printf(请输入管理员账号:);while (c = getch() != r)if (isprint(c) & i 0)/如果是退格字符时i-;putchar(b);putchar( );putchar(b);putchar(n);accounti = 0;i = 0;printf(请输入管理员密码:);while(c=getch()!=r)if (isprint(c) & i 0)i-;putchar(b);putchar( );putchar(b);putchar(n);passwordi = 0;if (!strcmp(account, 123456789ab) & !strcmp(password, 123456)printf(登陆成功!n);printf(按任意键继续以下操作.);getchar();pass = 0;InitInterface();elseprintf(登陆失败!请重新输入账号和密码或返回n);LABEL_BUNDLE labels;HOT_AREA areas;SMALL_RECT rcPop;COORD pos;WORD att;char *pCh = 继续输入 返回 ;int iHot = 1;pos.X = strlen(pCh0) + 6;pos.Y = 7;rcPop.Left = (SCR_COL - pos.X) / 2 + 3;rcPop.Right = rcPop.Left + pos.X - 7;rcPop.Top = (SCR_ROW - pos.Y) / 2 + 11;rcPop.Bottom = rcPop.Top + pos.Y - 8;att = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; /*白底黑字*/labels.num = 1;labels.ppLabel = pCh;COORD aLoc = rcPop.Left, rcPop.Top , rcPop.Left + 5, rcPop.Top + 5 ;labels.pLoc = aLoc;areas.num = 2;SMALL_RECT aArea = rcPop.Left , rcPop.Top ,rcPop.Left + 7, rcPop.Top , rcPop.Left + 34, rcPop.Top ,rcPop.Left + 37, rcPop.Top ;char aSort = 0, 0 ;char aTag = 1, 2 ;areas.pArea = aArea;areas.pSort = aSort;areas.pTag = aTag;PopUp(&rcPop, att, &labels, &areas);pos.X = rcPop.Left + 1;pos.Y = rcPop.Top + 4;if (DealInput(&areas, &iHot) = 13 & iHot = 1)deal1 = 1;elsedeal1 = 0;PopOff();InitInterface();3.3.3相关截图1. 账号密码输入错误提示及等待用户选择2. 账号密码输入成功3.3.4注:密码及账号简便起见,该系统只录入一个管理员账号及其对应的密码,为账号:123456789ab密码:1234563.4添加数据函数(AddData()通过管理员的验证后便可以添加数据了。输入数据不能随便,针对用户的错误输入要能给出一定的提示,在这里由于项目大小和时间限制,我们并未考虑全部的用户错误输入。3.4.1用户输入控制用户输入控制主要为了防止用户的输入造成程序死机之类的严重后果,对用户每次输入的有效字段长度进行了限制,对超出部分进行了丢弃。其次还对用户输入的实际意义进行了判断,例如添加数据时检查该编号是否已经存在(假定在该系统的默认中编号是唯一的,且不一定是顺序排列的)。下面给予举例说明:对于楼盘数据的添加,我们用了以下程序段:newestate = (ESTATE_NODE*)malloc(sizeof(ESTATE_NODE);printf(-);find = 1;while (find)printf(t输入楼盘编号(不超过9位数)t);scanf(%9s, newestate-estate_id);while (getchar() != n);/*如果输入超过限制,通过该语句刷新输入缓冲区*/estate = hd;while (estate != NULL&strcmp(estate-estate_id, newestate-estate_id) != 0)estate = estate-next;if (estate != NULL)find = 1;printf(t对不起,您输入的楼盘编号已存在,请重新输入!n);elsefind = 0;printf(-);printf(t输入楼盘名称ttt);scanf(%19s, newestate-name);while (getchar() != n);printf(-);printf(t输入城区ttt);scanf(%9s, newestate-city);while (getchar() != n);printf(-);printf(t输入楼盘地址ttt);scanf(%29s, newestate-address);while (getchar() != n);printf(-);printf(t输入开发商ttt);scanf(%19s, newestate-developer);while (getchar() != n);printf(-);printf(t输入物业公司ttt);scanf(%19s, newestate-management_company);while (getchar() != n);printf(-);newestate-bnext = NULL;newestate-next = NULL;对于输入的每一个数据我们都进行了输入判断,主要围绕了两个方面:1. 输入的楼盘编号不能与已有数据重复(即满足实际意义)2. 输入的数据不会造成内存溢出(即满足程序的完善性)3.4.2插入链表设计1. 插入楼盘数据插入楼盘数据较为简单,利用以下代码段即可。newestate-next = hd;hd = newestate;2. 插入楼栋数据ESTATE_NODE *pestate = SeekEstateNode(hd, newbuild-estate_id);if (pestate=NULL)free(newbuild);printf(ttt输入有误,该楼栋所对应的楼盘不存在,插入失败n); elsenewbuild-next = pestate-bnext;pestate-bnext = newbuild;printf(ttttttt插入成功n);其中SeekEstateNode函数以根据楼盘编号查找到对应的楼盘结点,未找到即返回NULL。3. 插入房屋数据BUILD_NODE* pbuild = SeekBuildNode(hd, newhouse-estate_id, newhouse-build_id);if (pbuild = NULL)free(newhouse);printf(ttt输入有误,该房屋所对应的楼栋不存在,插入失败n);elsenewhouse-next = pbuild-hnext;pbuild-hnext = newhouse;printf(tttttt插入成功n);其中SeekBuildNode函数以根据楼盘编号和楼栋编号查找到对应的楼栋结点,未找到即返回NULL。3.4.3相关截图1. 插入楼盘数据成功2. 添加的楼盘数据中楼盘编号已有(即数据错误)3. 添加楼房数据失败3.5删除数据函数(DeleteData()通过管理员验证便可以删除数据了,删除一项数据分为两个步骤,首先先找到这项数据(以编号为查找依据),然后再删除这个目标结点。查找过程利用SeekEstateNode(),SeekBuildNode(),SeekHouseNode()函数实现,以下主要介绍删除数据结点的函数设计。3.5.1删除楼盘数据函数(DelEstateNode()DelEstateNode()函数以头指针的地址(因为头指针有可能会改变)和楼盘号作为参数3.5.1.1流程设计3.5.1.2程序代码/*函数名称:DelEstatelNode*函数功能:在十字链表中删除指定的楼盘信息结点*输入参数:指向主链头指针的指针,楼盘编号*函数说明:*返回值:BOOL型数据,TRUE表示删除成功,FALSE表示删除失败*/BOOL DelEstateNode(ESTATE_NODE* phead, char* estateid)ESTATE_NODE* pbefore = *phead;ESTATE_NODE* p = *phead;while (p != NULL & strcmp(p-estate_id, estateid)pbefore = p;p = p-next;if (!p)return FALSE;/找到且为p所定位if (p = *phead) /如果被删结点是头指针*phead = p-next;elsepbefore-next = p-next;BUILD_NODE* pbuild = p-bnext;while (pbuild)HOUSE_NODE* phouse=pbuild-hnext;while (phouse)HOUSE_NODE *temp = phouse;phouse = phouse-next;free(temp);BUILD_NODE* temp = pbuild;pbuild = pbuild-next;free(temp);free(p);return TRUE;3.5.1.3注意事项释放楼盘结点信息时不仅仅要释放楼盘结点信息,还要释放其所对应的楼栋结点信息和房屋结点信息。因为这是在检查阶段才发现的,所以在此特作强调。3.5.2删除楼栋数据函数(DelBuildNode()DelBuildNode()函数以头指针和楼盘楼栋编号作为实参传递,注意此时不必传递头指针地址,因为头指针在该过程中不会改变。3.5.2.1流程设计3.5.2.2程序代码/*函数名称:DelBuildNode*函数功能:在十字链表中删除指定的楼栋信息结点*输入参数:主链头指针,楼盘编号,楼栋编号*输出参数:无*函数说明:*返回值:BOOL型数据,TRUE表示删除成功,FALSE表示删除失败*/BOOL DelBuildNode(ESTATE_NODE*head, char* estateid, char* buildid)ESTATE_NODE* pestate;BUILD_NODE* p, *pbefore;pestate = SeekEstateNode(head, estateid);/定位到对应楼盘结点if (!pestate)return FALSE;elsep = pbefore = pestate-bnext;while (p != NULL & strcmp(p-build_id, buildid)pbefore = p;p = p-next;if (!p)return FALSE;/找到且为p所定位if (p = pestate-bnext) /如果被删结点是头指针pestate-bnext = p-next;elsepbefore-next = p-next;HOUSE_NODE* phouse = p-hnext;while (phouse)HOUSE_NODE* temp=phouse;phouse = phouse-next;free(temp);free(p);return TRUE;3.5.2.3注意事项释放楼栋结点信息时不仅仅释放楼栋结点信息,也要释放其对应的房屋结点信息。3.5.3删除房屋数据函数(DelHouseNode()DelHouseNode()函数以头指针和楼盘楼栋房屋编号作为实参传递,注意此时不必传递头指针地址,因为头指针在该过程中不会改变。3.5.3.1流程设计3.5.3.2程序代码/*函数名称:DelHouseNode*函数功能:在十字链表中删除指定的房屋信息结点*输入参数:hd主链头指针,楼盘编号,楼栋编号,房屋编号*输出参数:无*返回值:BOOL型数据,TRUE表示删除成功,FALSE表示删除失败*函数说明:*/BOOL DelHouseNode(ESTATE_NODE*head, char* estateid, char* buildid, char* houseid)BUILD_NODE* pbuild;HOUSE_NODE* p, *pbefore;pbuild = SeekBuildNode(head, estateid, buildid);/定位到对应楼栋结点if (!pbuild)return FALSE;elsep = pbefore = pbuild-hnext;while (p != NULL & strcmp(p-house_id, houseid)pbefore = p;p = p-next;if (!p)return FALSE;/找到且为p所定位if (p = pbuild-hnext) /如果被删结点是头指针pbuild-hnext = p-next;elsepbefore-next = p-next;free(p);return TRUE;3.5.4相关截图1.选择2.未查找到数据3.删除成功3.6修改数据函数(ModifyData()修改数据分为两个步骤,第一个步骤是根据用户的选择输入定位到要修改的楼盘/楼栋/房屋,其次便是根据用户的指定的数据项进行修改。下面讨论一些修改时的具体细节。3.6.1修改楼盘数据函数(ModifyEstate()修改楼盘数据的时候要注意一点:修改楼盘编号时,在其下的楼栋数据和房屋数据中的楼盘编号都要同时进行修改。为此,我们只需加一个循环进行控制即可。如下:while (pbuild)strcpy(pbuild-estate_id, pestate-estate_id);phouse = pbuild-hnext;while (phouse)strcpy(phouse-estate_id, pestate-estate_id);phouse = phouse-next;pbuild = pbuild-next;3.6.2修改楼栋数据函数(ModifyBuild()同上,只需注意到改变楼栋编号时候用一个循环来改变其所对应的房屋编号即可。phouse = pbuild-hnext;while (phouse)strcpy(phouse-build_id, pbuild-build_id);phouse = phouse-next;3.6.3修改房屋数据函数(ModifyHouse()该函数采用同样的界面设计和输入控制设计,再此不做赘述。3.6.4相关截图1.修改数据项选择2.修改楼盘信息数据选择3.7存储数据函数(SaveData()存储数据函数用于将十字链表中的数据以二进制格式输出到文件中更新存储,因此,文件打开方式应为”wb”,通过遍历链表的方式便可实现存储。所以,步骤简单的分为打开文件和遍历链表存储数据。3.7.1打开文件部分1.打开楼盘数据文件if (fp_estate = fopen(gp_estate_info_filename, wb) = NULL)fputs(打开楼盘数据文件出错!, stderr);exit(EXIT_FAILURE);2.打开楼栋数据文件if (fp_build = fopen(gp_build_info_filename, wb) = NULL)fputs(打开楼栋数据文件出错!, stderr);exit(EXIT_FAILURE);3.打开房屋数据文件if (fp_house = fopen(gp_house_info_filename, wb) = NULL)fputs(打开房屋数据文件出错!, stderr);exit(EXIT_FAILURE);3.7.2遍历链表存储数据1.存储楼盘信息,遍历一次即可pestate = hd;while (pestate)fwrite(pestate, sizeof(ESTATE_NODE), 1, fp_estate);pestate = pestate-next;2.存储楼栋信息,需往两个方向遍历pestate = hd;while (pestate)pbuild = pestate-bnext;while (pbuild)fwrite(pbuild, sizeof(BUILD_NODE), 1, fp_build);pbuild = pbuild-next;pestate = pestate-next;3.存储楼房信息,需遍历三个方向pestate = hd;while (pestate)pbuild = pestate-bnext;while (pbuild)phouse = pbuild-hnext;while (phouse)fwrite(phouse, sizeof(HOUSE_NODE), 1, fp_house);phouse = phouse-next;pbuild = pbuild-next;pestate = pestate-next;3.7.4相关截图保存成功提示3.7.3注意事项最好打开一个数据项的文件后立马进行数据的存储,否则容易造成数据的丢失。3.8备份数据函数(BackData()备份数据函数分为三个部分:第一,备份数据项选择部分;第二,提示用户输入目的文件名和文件路径;第三,拷贝部分。3.8.1备份数据项选择部分给予用户三个选择:1. 备份楼盘数据2. 备份楼栋数据3. 备份房屋数据建立热区并判断用户选择是哪一个,用特征量flag来标志,便于步骤三备份所对应的文件。3.8.2提示用户输入部分1.系统提示用户用路径加文件名的方式描述备份文件所存储的地方,并且举了一个例子便于用户理解:例如若要把文件另存为到桌面可输入如下路径:C:Users*Desktop*.dat2.系统还进行了错误提醒,当用户输入的路径或文件名无效时对用户进行警告,并且提示用户重新进行输入或者退出备份。相关部分代码如下:deal1=1;while (deal1)printf(-);printf(输入你要存储的路径和文件名,例如:C:Users*Desktop*.datn);printf(文件路径&文件名: );scanf(%s, filename);printf(-);if (newfp = fopen(filename, wb) = NULL)/打开新文件fputs(文件路径无效!请重新输入!, stderr);else进行文件的备份操作.char *pCh = 继续输入 返回 ;iHot = 1;pos.X = strlen(pCh0) + 6;pos.Y = 7;rcPop.Left = (SCR_COL - pos.X) / 2 + 3;rcPop.Right = rcPop.Left + pos.X - 7;rcPop.Top = (SCR_ROW - pos.Y) / 2 + 11;rcPop.Bottom = rcPop.Top + pos.Y - 8;att = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED; /*白底黑字*/labels.num = 1;labels.ppLabel = pCh;COORD aLoc = rcPop.Left, rcPop.Top , rcPop.Left + 5, rcPop.Top + 5 ;labels.pLoc = aLoc;areas.num
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论