学习之路——用callback增强链表模块来实现命令行菜单小程序V2.8

【zhanghughsw + 《软件工程(C编码实践篇)》MOOC课程作业http://mooc.study.163.com/course/USTC-1000002006

本文为网易云课堂课程《软件工程(C编码实践)》的实验报告,本次实验为在前几次实验(命令行菜单小程序)的基础上,将使用可重用链表模块来实现内部模块化。

附上一实验的链接:用可重用的链表模块来实现命令行菜单小程序V2.5

一.实验思路

本次实验的目的是在前些实验的基础上使用callback增强链表模块,实验任务主要有以下3点:
1.找出视频中quit指令无法退出的原因,并修改
2.使用callback增强链表模块
3.隐藏结构体定义

首先解决任务1,出现quit指令失败的直接原因是由于查找失败造成了,为什么会查找失败,从下面截图中可以看到这里写图片描述
用于遍历的循环——while的退出条件是 当前结点 != 尾结点,这样就导致了存在尾结点内的指令quit不能被访问,自然就无法实现quit功能,改写函数为
这里写图片描述
运行结果:
这里写图片描述
任务2、3在下面的报告中体现!

附小程序功能列表:
- time:获取当前的日期与时间
- calculation:进行加减乘除四则运算
- notepad :在当前文件夹创建并使用vim打开一个文本文档*.txt
- version:打印程序的版本号
- mac : 打开文件管理器nautilus
- explore :打开浏览器
- help :列出所有指令及解释
- help :列出所有指令及解释


二、代码实现

程序代码三个文件来进行代码编写,分别为menu.c linktable.c linktable.h

在本文件中实现主函数的编写,主要功能是输入的cmd字符获取与匹配

void main()
{
    InitMenuData(&head);
    while(1)
    {
        char cmd[CMD_MAX_LEN];
        printf("input a cmd number ->");
        scanf("%s", cmd);
        tDataNode *p = FindCmd(head, cmd);
        if(p == NULL)
        {
            printf("This is a wrong cmd!\n");
            continue;
        }
        if (strcmp(p->cmd, "help") != 0)
        {
            printf("%s - %s\n", p->cmd, p->desc);
        }
        if(p->handler != NULL)
        {
            p->handler();
        }
    }
}

本次实验menu.c文件中的主函数基本没有变化,变化的是在文件中修改了查找函数,以及添加了callback函数SearchCondition()

int SearchCondition(tLinkTableNode * pLinkTableNode, void * args)
{
    char * cmd = (char*)args;
    tDataNode * pNode = (tDataNode *)pLinkTableNode;
    if(strcmp(pNode->cmd, cmd) == 0)
    {
        return SUCCESS;
    }
    return FAILURE;
}

tDataNode* FindCmd(tLinkTable * head,char * cmd)
{
    return (tDataNode*)SearchLinkTableNode(head,SearchCondition,(void *)cmd);
}

自定义功能的存储方式如下:

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 = "time";
    pNode->desc = "You can use this cmd to get the localtime!";
    pNode->handler = Time;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "caculation";
    pNode->desc = "You can use this cmd to have a simple calculate";
    pNode->handler = Calculation;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "notepad";
    pNode->desc = "You can use this cmd to open a note file by vim";
    pNode->handler = Notepad;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "version";
    pNode->desc = "menu line v1.2 bu yiyu";
    pNode->handler = NULL;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "mgc";
    pNode->desc = "You can use this cmd to open the File System";
    pNode->handler = Mgc;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "explore";
    pNode->desc = "You can use this cmd to open the explore";
    pNode->handler = Explore;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "quit";
    pNode->desc = "Quit the menu";
    pNode->handler = Quit;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode * )pNode);

    return 0;
};

linktable.h

本文件用于编写链表以及链表节点的数据结构以及声明在其上的一系列操作,本次实验在其中添加了新方法的声明:SearchLinkTableNode(),同时对结构体的内部结构进行了隐藏
SearchCondition()

#ifndef _LINK_TABLE_H_
#define _LINK_TABLE_H_

#include <pthread.h>

#define SUCESS 0
#define FAILURE (-1)

typedef struct LinkTableNode
{
    struct LinkTableNOde * pNext;
}tLinkTableNode;

typedef struct LinkTable tLinkTable;

tLinkTable * CreateLinkTable();

int DeleteLinkTable(tLinkTable *pLinkTable);

int AddLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);

int DelLinkTable(tLinkTable *pLinkTable,tLinkTableNode * pNode);

tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);

tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);

tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable,int Condition(tLinkTableNode * pNode,void * args), void * args);
#endif

linktable.c

本文件具体定义了链表的各种操作以及指令所对应的操作,本次实验在其中加入了结构体的定义,以及优化修改了部分方法,添加了SearchLinkTableNode()的具体实现
定义结构体

typedef struct LinkTable
{
    tLinkTableNode *pHead;
    tLinkTableNode *pTail;
    int SumOfNode;
    pthread_mutex_t mutex;
};

CreateTable()——创建链表

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

AddLinkTableNode()——插入结点

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

GetLinkTableHead()——返回头结点

tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable) 
{
    if(pLinkTable == NULL)
    {
        return NULL;
    }
    return pLinkTable->pHead;
}

DelLinkTable()——删除链表

int DelLinkTable(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;
}

GetNextLinkTableNode()——返回下一节点

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

以及各项指令的功能函数

int Time()
{
    time_t now;
    struct tm *tm_now;
    time(&now);
    tm_now = localtime(&now);
    printf("now datetime:%d-%d-%d %d:%d:%d\n", tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
}

int Calculation()
{
    char ch;
    int num1, num2;
    printf("which calculations: + - * /:");
    scanf("%c", &ch);
    while (1)
    {
        scanf("%c", &ch);
        setbuf(stdin, NULL);
        if (ch == 'Q')
        {
            return 1;
        }
        else if (ch != '+' && ch != '-' && ch != '*' && ch != '/')
        {
            printf("Input Wrong!please input the one of '+','-','*','/'\n");
        }
        else
        {
            printf("You want to have a %c calculate,input the two number,separate by comma!\n", ch);
            break;
        }
    }
    scanf("%d,%d", &num1, &num2);
    if (ch == '+')
    {
        printf("%d+%d=%d\n", num1, num2, num1 + num2);
    }
    else if (ch == '-')
    {
        printf("%d-%d=%d\n", num1, num2, num1 - num2);
    }
    else if (ch == '*')
    {
        printf("%d*%d=%d\n", num1, num2, num1 * num2);
    }
    else if (ch == '/')
    {
        printf("%d/%d=%f\n", num1, num2, (float)num1 / num2);
    }
    else
    {
        printf("Input Wrong!");
        return -1;
    }
    return 0;
}

int Quit()
{
    exit(0);
}

int Notepad()
{
    system("touch ./*.txt");
    system("vim ./*.txt");
    return 0;
}

int Mgc()
{
    system("nautilus");
    return 0;
}

int Explore()
{
    system("firefox");
    return 0;
}

运行结果:

这里写图片描述

三、实验总结

本次实验是收获巨大的,让我了解了使用callback方法来增强链表模块,同时在实验过程中,巩固了链表的相关知识,特别是链表的插入、遍历等方面的知识。

复审代码
通过如下命令可以从Git版本库中拉取代码并编译运行

git clone https://github.com/zhanghughsw/zswlab.git
cd zswlab
cd lab5
gcc menu.c linktable.c -o menu
./menu

github:
https://github.com/zhanghughsw/zswlab

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中,回调函数(CallBack)是一种常见的编程模式。它的基本思想是,在某个方法中调用另一个方法,并将该方法作为参数传递进去,以便在后续的执过程中回调该方法。 下面简单介绍一下Java中实现CallBack的方法: 1.定义一个接口 首先,我们需要定义一个接口,该接口中包含一个回调方法。例如,我们定义一个名为CallBack接口,其中包含一个名为execute的回调方法。 ``` public interface CallBack { void execute(); } ``` 2.实现CallBack接口 接下来,我们需要实现CallBack接口。例如,我们定义一个名为Caller的类,其中包含一个名为registerCallBack的方法,该方法接受一个CallBack对象作为参数,并将其保存在Caller类中。 ``` public class Caller { private CallBack callBack; public void registerCallBack(CallBack callBack) { this.callBack = callBack; } public void doSomething() { // 在某个方法中调用回调方法 callBack.execute(); } } ``` 3.使用CallBack 最后,我们可以使用CallBack来完成特定的操作。例如,我们定义一个名为Main的类,该类实现CallBack接口中的execute方法,并使用Caller类来调用该方法。 ``` public class Main implements CallBack { public static void main(String[] args) { Caller caller = new Caller(); Main main = new Main(); caller.registerCallBack(main); caller.doSomething(); } @Override public void execute() { System.out.println("回调方法被调用了!"); } } ``` 在上面的代码中,我们首先创建了一个Caller对象和一个Main对象。然后,我们将Main对象注册到Caller对象中,并调用Caller对象的doSomething方法。在doSomething方法中,会调用CallBack接口中的execute方法,从而触发Main对象中的execute方法。 注意,这里的CallBack接口和Caller类是非常简单的示例,实际应用中可能需要更加复杂的实现方式。但是,基本的思是一致的:定义一个接口,实现接口并在其中实现回调方法,然后使用回调方法来完成特定的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值