软件工程课程实验报告:实验五
2017-10-23 21:43
176 查看
实验五:用callback增强链表模块来实现命令行菜单小程序V2.8
咖啡机《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006新创建一个目录lab5完成实验。
然后将lab5-1.tar.gz中的代码(即解压后lab5.1/目录下的源文件)直接放到lab5/目录下继续完成后面的实验内容。
一、实验要求
给lab5-1.tar.gz找bug,quit命令无法运行的bug利用callback函数参数使Linktable的查询接口更加通用
注意接口的信息隐藏
及时提交代码以防丢失
二、实验过程
1. 创建lab5文件夹,将lab5-1.tar.gz解压至文件夹下2. 编译代码并执行,发现
quit()命令无法正确执行
3. 从程序的主入口入手,进行代码审查
menu.c中的
main()函数及
InitMenuData(tLinkTable ** ppLinktable)函数
int InitMenuData(tLinkTable ** ppLinktable) { *ppLinktable = CreateLinkTable(); tDataNode* pNode = (tDataNode*)malloc(sizeof(tDataNode)); pNode->cmd = "help"; pNode->desc = "Menu List:"; pNode->handler = Help; AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode); pNode = (tDataNode*)malloc(sizeof(tDataNode)); pNode->cmd = "version"; pNode->desc = "Menu Program V1.0"; pNode->handler = NULL; AddLinkTableNode(*ppLinktable,(tLinkTable 4000 Node *)pNode); pNode = (tDataNode*)malloc(sizeof(tDataNode)); pNode->cmd = "quit"; pNode->desc = "Quit from Menu Program V1.0"; pNode->handler = Quit; AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode); return 0; } /* menu program */ tLinkTable * head = NULL; int main() { InitMenuData(&head); /* cmd line begins */ while(1) { printf("Input a cmd number > "); scanf("%s", cmd); tDataNode *p = FindCmd(head, cmd); if( p == NULL) { printf("This is a wrong cmd!\n "); continue; } printf("%s - %s\n", p->cmd, p->desc); if(p->handler != NULL) { p->handler(); } } }
可以看到,在
main()中,先初始化命令链表,
InitMenuData(tLinkTable ** ppLinktable)将quit命令的cmd和desc属性赋值。按照
main()的正常运行过程,输入quit,程序的输出应为”Quit from Menu Program v1.0”。
main()中初始化命令链表之后,便是一个用来等待用户输入命令、并进行相关处理的循环体。在循环中,注意到输入的cmd通过
FindCmd()函数查找命令链表对应的结点p,p不为空时输出结点,p为空时提示错误”This is a Wrong cmd”,这恰与我们目前程序quit的输出相同。因此,错误可能来源于
FindCmd()函数。
- menu.c中的
FindCmd()和
SearchCondition()函数
int SearchCondition(tLinkTableNode * pLinkTableNode) { tDataNode * pNode = (tDataNode *)pLinkTableNode; if(strcmp(pNode->cmd, cmd) == 0) { return SUCCESS; } return FAILURE; } /* find a cmd in the linklist and return the datanode pointer */ tDataNode* FindCmd(tLinkTable * head, char * cmd) { return (tDataNode*)SearchLinkTableNode(head,SearchCondition); }
在
FindCmd()中可以看到,调用了linktable.c中的
SearchLinkTableNode()函数,其代码如下:
/* * Search a LinkTableNode from LinkTable * int Conditon(tLinkTableNode * pNode); */ tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode)) { if(pLinkTable == NULL || Conditon == NULL) { return NULL; } tLinkTableNode * pNode = pLinkTable->pHead; while(pNode != pLinkTable->pTail) { if(Conditon(pNode) == SUCCESS) { return pNode; } pNode = pNode->pNext; } return NULL; }
函数中的循环体循环条件
while(pNode != pLinkTable->pTail)使得函数在到达命令链表尾部时,无法退出循环,无法访问最后一个结点。在这个程序中,最后一个结点就是quit命令。因此作以下修改(见代码中注释):
/* * Search a LinkTableNode from LinkTable * int Conditon(tLinkTableNode * pNode); */ tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode)) { if(pLinkTable == NULL || Conditon == NULL) { return NULL; } tLinkTableNode * pNode = pLinkTable->pHead; //更改循环体条件,当链表结点不为空,便可继续遍历链表寻找命令 while(pNode != NULL) { if(Conditon(pNode) == SUCCESS) { return pNode; } pNode = pNode->pNext; } return NULL; }
3. 再次编译运行,发现bug消失
4. 解决数据结构的通用型
menu.c中
将全局变量cmd[CMD_MAX_LEN]放入
main()函数内
int main() { InitMenuData(&head); //降低模块间的耦合 char cmd[CMD_MAX_LEN]; /* cmd line begins */ while(1) { printf("Input a cmd number > "); scanf("%s", cmd); tDataNode *p = FindCmd(head, cmd); if( p == NULL) { printf("This is a wrong cmd!\n "); continue; } printf("%s - %s\n", p->cmd, p->desc); if(p->handler != NULL) { p->handler(); } } }
修改
SearchCondition()的参数,传入cmd变量。
int SearchCondition(tLinkTableNode * pLinkTableNode,void * args) { char *cmd = (char *)args; tDataNode * pNode = (tDataNode *)pLinkTableNode; if(strcmp(pNode->cmd, cmd) == 0) { return SUCCESS; } return FAILURE; }
修改
FindCmd()函数:
/* find a cmd in the linklist and return the datanode pointer */ tDataNode* FindCmd(tLinkTable * head, char * cmd) { return (tDataNode*)SearchLinkTableNode(head, SearchCondition, (void *) cmd); }
在linktable.c中修改
SearchLinkTableNode()函数:
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode, void *args), void * args) { if(pLinkTable == NULL || Conditon == NULL) { return NULL; } tLinkTableNode * pNode = pLinkTable->pHead; while(pNode != NULL) { if(Conditon(pNode, args) == SUCCESS) { return pNode; } pNode = pNode->pNext; } return NULL; }
5. 隐藏重要数据结构实现
linktable.h中
在linktable.h接只提供结构体类型的声明,将结构体类型的定义放在linktable.c中。
/* * LinkTable Node Type */ typedef struct LinkTableNode tLinkTableNode; /* * LinkTable Type */ typedef struct LinkTable tLinkTable;
6. 编译运行
7. 将代码同步到github
Github地址:https://github.com/973301529/se/tree/master/lab5
三、实验总结
通过本次实验,软件开发过程中需要具备模块化思想,掌握了接口函数的作用。对于callback函数进行了简单的实践,体会到了它的优势。相关文章推荐
- 软件工程课程实验报告:实验三
- 软件工程课程实验报告:实验七
- 软件工程课程实验报告:课程总结
- 软件工程课程实验报告:实验四
- 软件工程实验报告 三
- 高级软件工程实验报告一
- 软件工程课程实验报告:实验二
- 软件工程课程实验报告:实验一
- 高级软件工程实验报告三
- JAVA课程实验报告 实验二 JAVA面向对象程序设计
- 操作系统存储管理实验课程设计报告
- C程序设计课程-第七次实验报告
- “软件工程(C编码实践篇)”实验报告【实验三:内部模块化的命令行菜单小程序V2.0】
- “软件工程(C编码实践篇)”实验报告(六)
- 操作系统课程实验六个(含实验报告和源代码)
- “软件工程(C编码实践篇)”实验报告【实验四:用可重用的链表模块来实现命令行菜单小程序V2.5】
- JAVA课程实验报告 实验三 敏捷开发与XP实践
- JAVA课程实验报告 实验五 Java网络编程及安全
- “软件工程(C编码实践篇)”实验报告(五)
- “软件工程(C编码实践篇)”实验报告【实验二:命令行菜单小程序V1.0】