咖啡机《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006
新创建一个目录lab5完成实验。
然后将lab5-1.tar.gz中的代码(即解压后lab5.1/目录下的源文件)直接放到lab5/目录下继续完成后面的实验内容。
quit()
命令无法正确执行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,(tLinkTableNode *)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;
}
将全局变量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;
}
/*
* LinkTable Node Type
*/
typedef struct LinkTableNode tLinkTableNode;
/*
* LinkTable Type
*/
typedef struct LinkTable tLinkTable;
Github地址:https://github.com/973301529/se/tree/master/lab5
通过本次实验,软件开发过程中需要具备模块化思想,掌握了接口函数的作用。对于callback函数进行了简单的实践,体会到了它的优势。