“软件工程(C编码实践篇)”实验报告
实验四:用可重用的链表模块来实现命令行菜单小程序V2.5
网易云课堂昵称: Arjen0130
《软件工程(C编码实践篇)》MOOC课程作业 http://mooc.study.163.com/course/USTC-1000002006
实验报告原链接地址:http://note.youdao.com/noteshare?id=34e9c5ee0afe055b2b83b5501c6fcd95&sub=503CCB201F82416FB6780968CA6AE688
1. 实验内容和要求
1.1 实验内容
用可重用的链表模块来实现命令行菜单小程序V2.5
1.2 实验要求
用可重用的链表模块来实现命令行菜单小程序,执行某个命令时调用一个特定的函数作为执行动作;
链表模块的接口设计要足够通用,命令行菜单小程序的功能保持不变;
可以将通用的Linktable模块集成到我们的menu程序中;
接口规范。
2. 实验的思路和具体过程
2.1 实验的思路
看完实验四的相关学习视频以后,初步了解了可重用链表模块的设计方法。依照视频讲解,在制定完成链表模块的各个函数接口以后,就可以用链表模块替换掉实验三中的顺序表接口,从而完成本次实验。
2.2 实验的具体过程
1)使用实验1中创建好的本地仓库,添加lab4文件夹,并在lab4目录下创建、编写相关的头文件以及源文件。期间,根据实际需要,会重用前面实验编写好的相关代码文件;
2)创建、编写相关文件的过程中,完成可重用链表模块的相关代码为主要工作内容;将实验3中的顺序表替换为可重用链表为次主要工作内容;
3)编译通过后,进行测试。待测试通过之后,将步骤1)、2)中完成的头文件和源文件提交到本地仓库;
4)将本地仓库的变化更新到GitHub远端仓库。
3. 关键代码
3.1 main函数关键代码
... ...
typedef struct CmdInfo
{
    char * cmd;
    char * desc;
    void (*handler)();
}tCmdInfo;

tLinkTable * pLinkTable = NULL;
tDataNode * head = NULL;

tCmdInfo cmdInfo[CMD_NUM] =
{
    {"help", "this is help cmd", help},
    {"read", "this is read cmd", read},
    {"write", "this is write cmd", write},
    {"get", "this is get cmd", get},
    {"pull", "this is pull cmd", pull},
    {"push", "this is push cmd", push},
    {"compare", "this is compare cmd", compare},
    {"put", "this is put cmd", put},
    {"quit", "this is quit cmd", quit}
};

/*
 * Initialize the pLinkTable with the menu command
 */
void InitMenuTable(tLinkTable * pLinkTable);

int main()
{
    pLinkTable = CreateLinkTable();
    if(NULL == pLinkTable)
    {
        printf("CreateLinkTable Error...\n");
        exit(1);
    }
    InitMenuTable(pLinkTable);
    head = (tDataNode *)pLinkTable->pHead;

    char cCmd[CMD_MAX_LEN];
    while(1)
    {
        printf("Input a cmd > ");
        scanf("%s", cCmd);
        tDataNode *p = FindCmd(head, cCmd);
        if (NULL == p)
        {
            printf("Undefined command...\n");
            continue;
        }
        printf("%s - %s\n", p->cmd, p->desc);
        if(NULL != p->handler)
        {
            p->handler();
        }
    }
    return 0;
}

/*
 * Initialize the pLinkTable with the menu command
 */
void InitMenuTable(tLinkTable * pLinkTable)
{
    for(int i = 0; i < CMD_NUM; i++)
    {
        tDataNode * pNode = (tDataNode *)malloc(sizeof(tDataNode));
        if(NULL == pNode)
        {
            printf("malloc Error...\n");
            exit(1);
        }
        pNode->cmd = (cmdInfo[i]).cmd;
        pNode->desc = (cmdInfo[i]).desc;
        pNode->handler = (cmdInfo[i]).handler;
        if(1 == AddLinkTableNode(pLinkTable, (tLinkTableNode *) pNode))
        {
            printf("AddLinkTableNode Error...\n");
            exit(1);
        }
    }
}
3.2 可重用链表模块关键代码
/*
 * Create a LinkTable
 * return value: If success, return the poiner points to the created LinkTable, otherwise return NULL
 */
tLinkTable * CreateLinkTable()
{
    tLinkTable * p = (tLinkTable *)malloc(sizeof(tLinkTable));
    if(NULL == p)
        return NULL;
    p->pHead = NULL;
    p->pTail = NULL;
    p->sumOfNode = 0;
    return p;
}

/*
 * Delete a LinkTable, and free the memory
 * return value: Always zero
 */
int DeleteLinkTable(tLinkTable * pLinkTable)
{
    if(NULL == pLinkTable)
        return 0;
    tLinkTableNode * pNode = pLinkTable->pHead;
    tLinkTableNode * pHead = pNode;
    while(NULL != pNode)
    {
        pHead = pHead->pNext;
        free(pNode);
        pNode = pHead;
    }
    free(pLinkTable);
    return 0;
}

/*
 * Add a LinkTableNode to LinkTable
 * return value: If success, return zero, otherwise return one
 */
int AddLinkTableNode(tLinkTable * pLinkTable, tLinkTableNode * pNode)
{
    if((NULL == pLinkTable) || (NULL == pNode))
        return 1;
    tLinkTableNode * pHead = pLinkTable->pHead;
    tLinkTableNode * pTail = pLinkTable->pTail;

    pNode->pNext = NULL;
    if(NULL == pHead)
    {
        pLinkTable->pHead = pLinkTable->pTail = pNode;
    }
    else
    {
        pLinkTable->pTail->pNext = pNode;
        pLinkTable->pTail = pNode;
    }
    pLinkTable->sumOfNode += 1;
    return 0;
}
注:与实验3相比,实验4的其余部分改动很小或基本没有改动。
4. 相关截图
4.1 实验结果截图

注:每一条命令执行后,共打印出来两行提示信息。其中,第一行为命令的描述信息;第二行为命令函数执行后,函数体内printf函数的打印信息。
4.2 关键代码截图

















4.3 操作过程截图
4.3.1 创建的各个头文件和源文件

4.3.2 将工作目录中的文件添加并提交到Git本地仓库

4.3.3 将本地仓库的变化提交到远端仓库



4.4 复现操作截图

5. 实验过程中遇到的疑惑、困难及处理方法
本次实验过程,主要的困难还在于对可重用链表模块相关代码的编写与调试。特别是C语言中与指针相关部分的处理,如果对指针的使用不当,虽然编译、链接都可以通过,但测试过程中很容易发生段错误问题。遇到这种情况时,可以使用GDB调试工具对代码进行调试,在调试过程中可以监视相关变量的值的变化,进而可以判断出程序代码中哪里出现了问题。
6. 实验总结
通过本次实验,学习了可重用链表的实现方法,同时,也初步练习了GDB调试工具的使用。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐