软件工程(C编码实践篇)”实验报告 实验五:用callback增强链表模块来实现命令行菜单小程序V2.8

来源:互联网 发布:遗传算法svm 特征选择 编辑:程序博客网 时间:2024/05/29 16:25

实验五:用callback增强链表模块来实现命令行菜单小程序V2.8

学号:SA17225153

网易云课堂昵称:ykt1505394686006 + 《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006

github地址:https://github.com/kongziyang/Senior-Software-Enginnering


一 实验要求

  • 给lab5-1.tar.gz找bug,quit命令无法运行的bug

  • 利用callback函数参数使Linktable的查询接口更加通用

  • 注意接口的信息隐藏


二 实验过程

1.新建一个目录lab5,将所给压缩包复制至目录下并解压。


2.编译并运行所给代码,发现输入quit指令后程序没有退出。

3.对该错误进行debug。

   首先对打印出错的语句进行追踪,发现是由于FindCmd函数返回的指针为空,导致*p==NULL,因此执行了出错语句。追踪至FindCmd函数的具体实现可知该函数依赖于SearchLinkTableNode函数的返回,于是查看SearchLinkTableNode的实现如下:

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;}

第一个if语句是对链表进行初步的判断,如果为空链表则返回NULL。接下来*pNode获取链表的头节点并进入while循环,当pNode不是尾结点时,循环继续,并且不符合循环内的if条件的将继续遍历下一个结点。这里便注意到了一个bug,即链表的尾节点没能够进入循环的得到判断if条件的机会,而恰恰quit指令作为指令链表的最后一个结点并没有能够被识别到。所以接下来对循环判断条件进行修改,修改为
pNode != NULL
此时,pNode能够取到链表每一个结点。代码改动前后如下面两图所示:


改动前:

改动后:

将改动后的代码重新进行编译并运行,得到的结果如下图所示,quit指令执行成功。


4.将之前编写的menu代码整合至本次实验的文件中。menu.c和linktable.c和linktable.h代码如下:

 
menu.c

#include <stdio.h>#include <stdlib.h>#include "linktable.h"int Help();int Quit();int Add();int Sub();#define CMD_MAX_LEN 128#define DESC_LEN    1024#define CMD_NUM     10char cmd[CMD_MAX_LEN];/* data struct and its operations */typedef struct DataNode{    tLinkTableNode * pNext;    char*   cmd;    char*   desc;    int     (*handler)();} tDataNode;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);}/* show all cmd in listlist */int ShowAllCmd(tLinkTable * head){    tDataNode * pNode = (tDataNode*)GetLinkTableHead(head);    while(pNode != NULL)    {        printf("%s - %s\n", pNode->cmd, pNode->desc);        pNode = (tDataNode*)GetNextLinkTableNode(head,(tLinkTableNode *)pNode);    }    return 0;}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 V2.8";    pNode->handler = NULL;     AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode);    pNode = (tDataNode*)malloc(sizeof(tDataNode));    pNode->cmd = "quit";    pNode->desc = "Quit from Menu Program V2.8";    pNode->handler = Quit;     AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode);    pNode = (tDataNode*)malloc(sizeof(tDataNode));    pNode->cmd = "add";    pNode->desc = "add two numbers";    pNode->handler = Add;    AddLinkTableNode(*ppLinktable,(tLinkTableNode *)pNode);    pNode=(tDataNode*)malloc(sizeof(tDataNode));    pNode->cmd = "sub";    pNode->desc = "make a sub of two numbers";    pNode->handler = Sub;    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();        }       }}int Help(){    ShowAllCmd(head);    return 0; }int Quit(){    exit(0);}int Add(){    int a,b;    printf("please input two numbers:\n");    scanf("%d %d",&a,&b);    int c = a+b;    printf("Result:a+b= %d\n",c);    return 0;}int Sub(){    int a,b;    printf("Please input two numbers:\n");    scanf("%d %d",&a,&b);    int c=a-b;    printf("Result:a-b= %d\n",c);    return 0;}


linktable.c

#include<stdio.h>#include<stdlib.h>#include"linktable.h"/* * Create a LinkTable */tLinkTable * CreateLinkTable(){    tLinkTable * pLinkTable = (tLinkTable *)malloc(sizeof(tLinkTable));    if(pLinkTable == NULL)    {        return NULL;    }    pLinkTable->pHead = NULL;    pLinkTable->pTail = NULL;    pLinkTable->SumOfNode = 0;    pthread_mutex_init(&(pLinkTable->mutex), NULL);    return pLinkTable;}/* * Delete a LinkTable */int DeleteLinkTable(tLinkTable *pLinkTable){    if(pLinkTable == NULL)    {        return FAILURE;    }    while(pLinkTable->pHead != NULL)    {        tLinkTableNode * p = pLinkTable->pHead;        pthread_mutex_lock(&(pLinkTable->mutex));        pLinkTable->pHead = pLinkTable->pHead->pNext;        pLinkTable->SumOfNode -= 1 ;        pthread_mutex_unlock(&(pLinkTable->mutex));        free(p);    }    pLinkTable->pHead = NULL;    pLinkTable->pTail = NULL;    pLinkTable->SumOfNode = 0;    pthread_mutex_destroy(&(pLinkTable->mutex));    free(pLinkTable);    return SUCCESS;}/* * Add a LinkTableNode to LinkTable */int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode){    if(pLinkTable == NULL || pNode == NULL)    {        return FAILURE;    }    pNode->pNext = NULL;    pthread_mutex_lock(&(pLinkTable->mutex));    if(pLinkTable->pHead == NULL)    {        pLinkTable->pHead = pNode;    }    if(pLinkTable->pTail == NULL)    {        pLinkTable->pTail = pNode;    }    else    {        pLinkTable->pTail->pNext = pNode;        pLinkTable->pTail = pNode;    }    pLinkTable->SumOfNode += 1 ;    pthread_mutex_unlock(&(pLinkTable->mutex));    return SUCCESS;}/* * Delete a LinkTableNode from LinkTable */int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode){    if(pLinkTable == NULL || pNode == NULL)    {        return FAILURE;    }    pthread_mutex_lock(&(pLinkTable->mutex));    if(pLinkTable->pHead == pNode)    {        pLinkTable->pHead = pLinkTable->pHead->pNext;        pLinkTable->SumOfNode -= 1 ;        if(pLinkTable->SumOfNode == 0)        {            pLinkTable->pTail = NULL;        }        pthread_mutex_unlock(&(pLinkTable->mutex));        return SUCCESS;    }    tLinkTableNode * pTempNode = pLinkTable->pHead;    while(pTempNode != NULL)    {            if(pTempNode->pNext == pNode)        {            pTempNode->pNext = pTempNode->pNext->pNext;            pLinkTable->SumOfNode -= 1 ;            if(pLinkTable->SumOfNode == 0)            {                pLinkTable->pTail = NULL;            }            pthread_mutex_unlock(&(pLinkTable->mutex));            return SUCCESS;            }        pTempNode = pTempNode->pNext;    }    pthread_mutex_unlock(&(pLinkTable->mutex));    return FAILURE;}/* * 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;}/* * get LinkTableHead */tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable){    if(pLinkTable == NULL)    {        return NULL;    }        return pLinkTable->pHead;}/* * get next LinkTableNode */tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode){    if(pLinkTable == NULL || pNode == NULL)    {        return NULL;    }    tLinkTableNode * pTempNode = pLinkTable->pHead;    while(pTempNode != NULL)    {            if(pTempNode == pNode)        {            return pTempNode->pNext;            }        pTempNode = pTempNode->pNext;    }    return NULL;}

linktable.h

#ifndef _LINK_TABLE_H_#define _LINK_TABLE_H_#include <pthread.h>#define SUCCESS 0#define FAILURE (-1)/* * LinkTable Node Type */typedef struct LinkTableNode{    struct LinkTableNode * pNext;}tLinkTableNode;/* * LinkTable Type */typedef struct LinkTable{    tLinkTableNode *pHead;    tLinkTableNode *pTail;    intSumOfNode;    pthread_mutex_t mutex;}tLinkTable;/* * Create a LinkTable */tLinkTable * CreateLinkTable();/* * Delete a LinkTable */int DeleteLinkTable(tLinkTable *pLinkTable);/* * Add a LinkTableNode to LinkTable */int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);/* * Delete a LinkTableNode from LinkTable */int DelLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);/* * Search a LinkTableNode from LinkTable * int Conditon(tLinkTableNode * pNode); */tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int Conditon(tLinkTableNode * pNode));/* * get LinkTableHead */tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);/* * get next LinkTableNode */tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);#endif /* _LINK_TABLE_H_ */

5.将加上自己扩展的代码进行编译并执行。

6.将代码提交至github上,利用git add添加文件,然后git commit -m 基数说明,最后进行git push即可。


如图为提交成功后github的截图,


 三 实验总结

     这次实验主要学习了call-back回调机制。当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。这个机制不同于我们平时的编码方式,所以应该多理解,因为回调有很大的灵活性,对以后的编程还是对一些更加复杂的代码或是框架理解时将大有作用。
阅读全文
0 0
原创粉丝点击