高级软件工程lab5-----用callback增强链表模块来实现命令行菜单小程序V2.8

高级软件工程lab5-----用callback增强链表模块来实现命令行菜单小程序V2.8

git地址:https://github.com/phny/lab5.git



实验步骤:

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

1,首先将文件下载下来进行查看



编译项目并运行,发现quit命令确实是无法使用


于是仔细检查代码出现这一问题的原因,发现问题出现在linktable.c中的SearchLinkTableNode中,while循环条件while(pNode != pLinkTable -> pTail)使得函数在找到链表最后一个节点时即退出循环,因此无法访问最后一个节点.将while(pNode != pLinkTable -> pTail)改为while(pNode != NULL)即可,修改后再次编译项目运行,我们发现quit命令已经可以正常使用。


运行修改后的项目:




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

具体的代码如下所示:

menu.c代码:


/************************************************************************/
/*  Copyright(C) mclab.com SSE@USTC , 2017/10/20    */
/*  FILENAME :menu.c     */
/*  PRINCIPAL AUTHOR:heyulin     */
/*  SUBSYSTEM NAME:mene     */
/*  MODULE NAME:menu     */
/*  LANGUAGE :C         */
/*  TARGET ENVIRONMENT:ANY     */
/*  DATE OF FIRST RELEASE:2017/10/20     */
/*  DESCRIPTION:This is a program      */ 

/************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "linktable.h"


#define CMD_MAX_LEN 128
#define DESC_LEN    1024
#define CMD_NUM     10


void help();
void add();
void sub();
void max();
void min();
void ls();
void quit();


/* data struct and its operations */
typedef struct DataNode
{
    tLinkTableNode* pNext;
    char*   cmd;
    char*   desc;
    int     (*handler)();
} tDataNode;
int SearchCondition(tLinkTableNode* pLinkTableNode, void* args)
{
    char *cmd = (char*)args;
    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, (void*)cmd);
}
/* 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 = "help!";
    pNode->handler = help;
    AddLinkTableNode(*ppLinktable, (tLinkTableNode*)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "add";
    pNode->desc = "addition";
    pNode->handler = add; 
    AddLinkTableNode(*ppLinktable, (tLinkTableNode*)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "sub";
    pNode->desc = "sub";
    pNode->handler = sub; 
    AddLinkTableNode(*ppLinktable, (tLinkTableNode*)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "ls";
    pNode->desc = "list";
    pNode->handler = ls; 
    AddLinkTableNode(*ppLinktable, (tLinkTableNode*)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "max";
    pNode->desc = "max";
    pNode->handler = max; 
    AddLinkTableNode(*ppLinktable, (tLinkTableNode*)pNode);
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "min";
    pNode->desc = "min";
    pNode->handler = min; 
    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);


    return 0; 
}
/* menu program */
tLinkTable* head = NULL;
int main()
{
    InitMenuData(&head); 
   /* cmd line begins */
    while(1)
    {
        char cmd[CMD_MAX_LEN];
        printf("please input a cmd >\n");
        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();
        }


    }
}


void help()
{
    ShowAllCmd(head);
}


void add()
{
    double num1;
    double num2;
    double result;


    printf("Addition!Please input two numbers!\n");
    printf("Use 'Blank' or 'Enter' to divide the two numbers.\n");
    scanf("%lf%lf", &num1, &num2);
    result=num1+num2;
    printf("%.2lf\n", result);
}


void sub()
{    
    double minuend;
    double meiosis;
    double result;


    printf("subtraction!Please input two numbers!\n");
    printf("Use 'Blank' or 'Enter' to divide the two numbers.\n");
    scanf("%lf%lf", &minuend, &meiosis);
    result=minuend-meiosis;
    printf("%.2lf\n", result);
}


void mul()
{    
    double num1;
    double num2;
    double result;


    printf("Multiplication!Please input two numbers!\n");
    printf("Use 'Blank' or 'Enter' to divide the two numbers.\n");
    scanf("%lf%lf", &num1, &num2);
    result=num1*num2;
    printf("%.2lf\n", result);
}


 void divi()
{   
    double dividend;
    double divisor;
    double result;


    printf("Divition!Please input two numbers!\n");
    printf("Use 'Blank' or 'Enter' to divide the two numbers.\n");
    scanf("%lf%lf", &dividend, &divisor);
    if(divisor==0)
    {
        printf("Error!Dividor can not be zero!\n");
    }
    result=dividend / divisor;
    printf("%.2lf\n", result);


 }


void max()
{
    int a,b;
    int max;
    printf("please enter two integers:\n");
    printf("Use 'Blank' or 'Enter' to divide the two numbers.\n");
    scanf("%d",&a);
    scanf("%d",&b);
    if(a>b)
        max=a;
    else
        max=b;
    printf("the maximum of %d and %d is %d\n",a,b,max);
}


void min()
{
    int a,b;
    int min;
    printf("please enter two integers:\n");
    scanf("%d",&a);
    scanf("%d",&b);
    if(a<b)
         min=a;
    else
        min=b;
    printf("the minimum of %d and %d is %d\n",a,b,min);
}


void ls()
{
    system("ls");
}


void Error()

    printf("Command not found!\n");
}


void quit()
{
    exit(0);
}



linktable.c代码:

/************************************************************************/
/* Copyright(C) mclab.com SSE@USTC , 2017/10/20    */
/* FILENAME :menu.c     */
/* PRINCIPAL AUTHOR:heyulin     */
/* SUBSYSTEM NAME:mene     */
/* MODULE NAME:menu     */
/* LANGUAGE :C         */
/* TARGET ENVIRONMENT:ANY     */
/* DATE OF FIRST RELEASE:2017/10/20     */
/* DESCRIPTION:This is a program     */

/************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include"linktable.h"
struct LinkTable
{
    tLinkTableNode *pHead;
    tLinkTableNode *pTail;
    int         SumOfNode;
    pthread_mutex_t mutex;
};
/*
 * 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,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;
}
/*
 * 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代码:



/************************************************************************/
/* Copyright(C) mclab.com SSE@USTC , 2017/10/20    */
/* FILENAME :menu.c     */
/* PRINCIPAL AUTHOR:heyulin     */
/* SUBSYSTEM NAME:mene    */
/* MODULE NAME:menu  */
/* LANGUAGE :C       */
/* TARGET ENVIRONMENT:ANY   */
/* DATE OF FIRST RELEASE:2017/10/20 */
/* DESCRIPTION:This is a program   */
/************************************************************************/


/*
 * Revision log:
 *
 * Created by Wang Shiqing,2017/10/18
 *
 */


#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 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,void * args),void *args);
/*
 * get LinkTableHead
 */
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);
/*
 * get next LinkTableNode
 */
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);
#endif /* _LINK_TABLE_H_ */


这次使用callback函数参数使得linktable查询接口更加通用,更加符合了接口设计可重用的原则与特点,符合软件工程编码规范。

在文件添加到本地的版本库中去:


提交到远程版本库中:


三,Code Review

把项目从github上clone 下来


测试项目是否能够正常运行:


四,实验总结

1,回调函数的使用是的查询链表的接口变得更加通用,同时也增加了代码的健壮性与可维护性。

2,回调函数使得程序的整个处理流程更加清晰易懂,实现了代码的可重用性与低耦合的要求

3,这次实验提高了自己的编码能力的同时,也学会了一些接口设计遵循的原则和技巧,懂得了好的代码就是要经过反复的设计和不断地优化来实现了的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值