【实验报告】高软实验5

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

github地址:https://github.com/JerryLittleBear/experiment.git


【实验目的】:


1、给未修改找bug,quit命令无法运行的bug

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

3、隐藏接口信息


【实验流程】:


1、找到quit命令无法运行的BUG

    我通过将自建函数void say();写进InitMenuData函数,此时say函数位于链表的最后一个结点。


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

    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "say";
    pNode->desc = "anything is ok";
    pNode->handler = say;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode* )pNode);

    return 0;
}



        此时发现quit可以运行,而say无法运行了。

这就说明bug应该在各个链表操作函数中。很快在SearchLinkTableNode函数中发现,在遍历链表的while循环中,while括号内的循环终止条件有问题:

    while(pNode != pLinkTable->pTali)

这个逻辑是当链表遍历到最后一个结点时(还未检查最后一个结点的数据)就退出循环了,这样对链表的最后一个结点就会直接跳过,所以链表存储的最后一个函数必然无法被找到、被执行。在老师给的代码中,quit函数就是最后一个链表结点,因此无法执行,我修改了InitMenuData后,say函数是最后一个链表结点,无法被执行。

要解决BUG,应修改循环条件为

    while(pNode != NULL)
这样,最后一个链表结点的数据就能够被遍历,quit就能够被SearchLinkTableNode函数找到,从而运行。


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

callback方式调用函数,简单来说就是定义一个函数A,它的参数列表中带有一个函数指针,这样以来,我们可以通过调用函数A,然后将其他函数B作为A的参数传递给A,这样A执行时,可以获得B的入口地址,从而在A执行过程中调用B。这种方式通常用于A、B函数不在同一个文件中,可以起到隐藏函数具体实现的作用。callback函数在本实验中应用如下:

tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int (*Conditon)(tLinkTableNode * pNode, void* cmd), void* arg)
{
    if(pLinkTable == NULL || Conditon == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pNode = pLinkTable->pHead;
    while(pNode != NULL)
    {    
        if(Conditon(pNode, arg) == SUCCESS)
        {
            return pNode;				    
        }
        pNode = pNode->pNext;
    }
    return NULL;
}
其中,SearchLinkTableNode函数的第二个参数就是函数指针Conditon,本程序通过这个函数指针来指向其他函数的入口地址,能间接调用其他函数。我在实验中发现两个要点:

1.C语言中函数指针中有参数和没参数都是可以的(但C++中函数指针的参数列表必须和它指向的函数一致)。

2.函数名即其入口地址,对函数名解引用依然是其入口地址,所以函数指针在使用时,解不解引用都可以,反正都是函数入口地址。

为了让接口更通用,我将用来接受命令行输入的全局变量char cmd[CMD_MAX_LEN];移到main函数中。为了做到这一点,必须修改多个函数的参数列表及其头文件,如:

tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int (*Conditon)(tLinkTableNode * pNode, void* cmd), void* arg)

tDataNode* FindCmd(tLinkTable * head, char * cmd)

int SearchCondition(tLinkTableNode * pLinkTableNode, void * cmd)
在他们的参数中都加入了一个字符指针或空指针,这样可以让接口更具有通用性。


3、隐藏接口信息

为达成该目标,需避免将链表数据结构的具体信息暴露给用户,所以将结构体信息:

struct LinkTable
{
    tLinkTableNode *pHead;
    tLinkTableNode *pTail;
    int			SumOfNode;
    pthread_mutex_t mutex;
};
放在linktable.c中,在头文件中用一句typedef struct LinkTable tLinkTable;将必要信息告诉用户。


我学到了】:

1、做了以下小实验:

#include <stdlib.h>

typedef struct time
{
    int* second;
    int minute;
}time;

int main()
{

    time* tiPtr;
    tiPtr = (time*)malloc(sizeof(time));
    printf("有具体值:%p\n", tiPtr);
    printf("有具体值:%d\n", tiPtr->minute);
    putchar(10);
    time* tiPtr1;
    printf("输出NULL:%p\n", tiPtr1);
    printf("内存段错误,引用了未知地址:%d\n", tiPtr1->minute);



    return 0;
}

这个实验说明了:指向结构体的指针必须有具体指向的时候才能通过->来引用成员,否则会引用到未知内存段,产生段错误。


2、做了另一个小实验:

#include <stdio.h>

int maxnum(int,int);

int main()
{
    int (*funcPtr)();

    funcPtr = maxnum;

    printf("函数名代表函数入口地址:%p\n", funcPtr);
    printf("函数指针解引用后还是其入口地址:%p\n", *funcPtr);

    return 0;
}

int maxnum(int a, int b)
{
    return a>b?a:b;
}
这个实验说明了,函数入口地址即函数名,是一个地址,但是对他解引用后还是它本身。


3、对callback函数做了一些调研

深入浅出剖析函数指针和回调函数:http://blog.csdn.net/morixinguan/article/details/65494239


【关键代码】:

代码分为3个文件:menu.c、linktable.c、linktable.h

源代码如下:

linktable.c:


#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, void* cmd);
 */
tLinkTableNode * SearchLinkTableNode(tLinkTable *pLinkTable, int (*Conditon)(tLinkTableNode * pNode, void* cmd), void* arg)
{
    if(pLinkTable == NULL || Conditon == NULL)
    {
        return NULL;
    }
    tLinkTableNode * pNode = pLinkTable->pHead;
    while(pNode != NULL)
    {    
        if(Conditon(pNode, arg) == 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;
}

menu.c:


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

int Help();
int Quit();
int say();

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



/* data struct and its operations */

typedef struct DataNode
{
    tLinkTableNode * pNext;
    char*   cmd;
    char*   desc;
    int     (*handler)();
} tDataNode;

int SearchCondition(tLinkTableNode * pLinkTableNode, void * cmd)
{
    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 = "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);

    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = "say";
    pNode->desc = "anything is ok";
    pNode->handler = say;
    AddLinkTableNode(*ppLinktable,(tLinkTableNode* )pNode);

    return 0;
}

/* menu program */

tLinkTable * head = NULL;

int main()
{
    InitMenuData(&head);
    char cmd[CMD_MAX_LEN];

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

    }
    return 0;
}

int Help()
{
    ShowAllCmd(head);
    return 0;
}

int Quit()
{
    exit(0);
}

int say()
{
    printf("good day!\n");
    return 0;
}
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 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* arg), void* arg);
/*
 * get LinkTableHead
 */
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);
/*
 * get next LinkTableNode
 */
tLinkTableNode * GetNextLinkTableNode(tLinkTable *pLinkTable,tLinkTableNode * pNode);

#endif /* _LINK_TABLE_H_ */



【实验截图】:

1、程序编译运行,help嵌套调用findCmd显示命令列表,quit函数退出程序,还有一些功能函数。




2、上传github进行版本控制。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值