将OSPF PNE代码中的链表的基本操作函数提取出来,并且进行了一些测试的实验。详细的测试文件位于./code/list.c中。下面将各个函数总结如下:

链表结构体

下面是链表结构体的定义。两个通用的链表结构体LINK和OSPF_GENERIC_NODE是所有链表操控函数的输入参数,其他链表结构体,例如OSPF,都需要强制类型转化为上面两个通用结构体,才能够作为参数传入链表操作函数。

typedef struct LINK {
    struct LINK *sptr_forward_link;
    struct LINK *sptr_backward_link;
} LINK;


/* used for pointer manipulation when inserting and removing nodes in a list */
typedef struct OSPF_GENERIC_NODE {
    struct OSPF_GENERIC_NODE *sptr_forward_link;
    struct OSPF_GENERIC_NODE *sptr_backward_link;
} OSPF_GENERIC_NODE;



typedef struct OSPF {
    struct OSPF *sptr_forward_link;
    struct OSPF *sptr_backward_link;
    int cnt;
} OSPF;

链表操作函数

下面是链表通用操作函数。注意,删除链表中的节点函数,形参链表首头位指针的指针,为什么需要这样呢?删除的节点,也许就是链表头所指的节点。也就是说,该形参不仅是输入参数,而且也可能是输出参数(在删除的节点为头节点时)。在测试函数main()中就有这样的一个实例,需要特别注意。


/*************************************************************************/
void ospf_add_entry_to_list(LINK * sptr_link, LINK * sptr_link_to_add)
{
    if (sptr_link == NULL) {
	return;
    }

    if (sptr_link_to_add == NULL) {
	return;
    }

    sptr_link_to_add->sptr_backward_link = sptr_link->sptr_backward_link;

    if (sptr_link->sptr_backward_link != NULL) {
	sptr_link->sptr_backward_link->sptr_forward_link =
	    sptr_link_to_add;
    } else {
	sptr_link->sptr_forward_link = sptr_link_to_add;
    }

    sptr_link->sptr_backward_link = sptr_link_to_add;

    sptr_link_to_add->sptr_forward_link = NULL;
}


/************************************************************************/
void ospf_delete_entry_from_list
    (
    LINK *sptr_list_link,
    LINK *sptr_link_to_delete
    )
    {
    if (sptr_list_link == NULL)
        {
        return;
        }

    if (sptr_link_to_delete == NULL)
        {
        return;
        }

    if ((sptr_link_to_delete->sptr_forward_link == NULL) &&
        (sptr_link_to_delete->sptr_backward_link == NULL)) /* 1 entry in list */
        {
        sptr_list_link->sptr_forward_link = NULL;
        sptr_list_link->sptr_backward_link = NULL;
        return;
        }

    if (sptr_link_to_delete->sptr_backward_link == NULL)
        {
        /* first entry in list */
        sptr_list_link->sptr_forward_link =
            sptr_link_to_delete->sptr_forward_link;
        }
    else
        {
        sptr_link_to_delete->sptr_backward_link->sptr_forward_link =
            sptr_link_to_delete->sptr_forward_link;
        }

    if (sptr_link_to_delete->sptr_forward_link == NULL) /* last entry in list */
        {
        sptr_list_link->sptr_backward_link =
            sptr_link_to_delete->sptr_backward_link;
        }
    else
        {
        sptr_link_to_delete->sptr_forward_link->sptr_backward_link =
            sptr_link_to_delete->sptr_backward_link;
        }

    sptr_link_to_delete->sptr_forward_link = NULL;
    sptr_link_to_delete->sptr_backward_link = NULL;
    }

/******************************************************************************/
void ospf_insert_node_in_list(OSPF_GENERIC_NODE * sptr_node,
			      OSPF_GENERIC_NODE * sptr_previous_node)
{
    sptr_node->sptr_backward_link = sptr_previous_node;
    sptr_node->sptr_forward_link = NULL;	/* always added at end */
    sptr_previous_node->sptr_forward_link = sptr_node;

    return;
}


/******************************************************************************/
void ospf_add_node_to_end_of_list(OSPF_GENERIC_NODE * sptr_node,
				  OSPF_GENERIC_NODE *
				  sptr_first_node_in_list)
{
    if (sptr_first_node_in_list->sptr_forward_link == NULL) {
	sptr_first_node_in_list->sptr_forward_link = sptr_node;

	sptr_first_node_in_list->sptr_backward_link = sptr_node;

	sptr_node->sptr_backward_link = sptr_first_node_in_list;

	sptr_node->sptr_forward_link = NULL;

	return;
    }

    ospf_add_entry_to_list((LINK *) sptr_first_node_in_list,
			   (LINK *) sptr_node);

    return;
}

/******************************************************************************/
void ospf_remove_node_from_list(OSPF_GENERIC_NODE ** ptr_sptr_first_node, OSPF_GENERIC_NODE * sptr_node)
{
    OSPF_GENERIC_NODE *sptr_previous_node;
    OSPF_GENERIC_NODE *sptr_next_node;


    sptr_previous_node = NULL;
    sptr_next_node = NULL;

    if ((*ptr_sptr_first_node == NULL) || (sptr_node == NULL))
	return;

    if (*ptr_sptr_first_node == sptr_node)
    {
        if (sptr_node->sptr_forward_link != NULL)
	{
            *ptr_sptr_first_node = sptr_node->sptr_forward_link;
			/* Mistral Added on July 25th */
	    if(*ptr_sptr_first_node) 
	    {
                (*ptr_sptr_first_node)->sptr_backward_link = 
                    sptr_node->sptr_backward_link;
	    }
	}
        else
	{
            *ptr_sptr_first_node = NULL;
	}

        sptr_node->sptr_forward_link = NULL;
        sptr_node->sptr_backward_link = NULL;

        return;
    }

    if ( *ptr_sptr_first_node != NULL )
    {
        ospf_delete_entry_from_list 
            ((LINK *) *ptr_sptr_first_node, (LINK *) sptr_node);
    }


    return;
}

/******************************************************************************/
OSPF_GENERIC_NODE *ospf_free_entire_list(OSPF_GENERIC_NODE * sptr_first_node_in_list)
{
    OSPF_GENERIC_NODE *sptr_node;
    OSPF_GENERIC_NODE *sptr_next_node;


    for (sptr_node = sptr_first_node_in_list; sptr_node != NULL;
	 sptr_node = sptr_next_node) {
	sptr_next_node = sptr_node->sptr_forward_link;

	ospf_remove_node_from_list((OSPF_GENERIC_NODE **) &sptr_first_node_in_list, sptr_node);

	free((void *) sptr_node);

	sptr_node = NULL;
    }

    return (NULL);
}

链表测试用例

下面为测试函数,用于测试上面的链表操作函数。有一个地方没有明白,销毁整个链表时,使用的是free((void *) sptr_node),指针的类型都改变了,free函数还知道我真正的链表结构体(本例中的OSPF结构体)大小吗?


void printList(OSPF* ptr)
{
    OSPF* ptr_node;

    printf("the list node: ");

    for(ptr_node = ptr;ptr_node != NULL; ptr_node = ptr_node->sptr_forward_link)
    {
	printf("%d->",ptr_node->cnt);
    }
    printf("NULL\n");

    return;
}


int main(int argc,char** argv)
{
    OSPF* ptr = NULL;
    OSPF* ptr_node = NULL;
    OSPF* ptr_node_del = NULL;

    /* init the list */
    if(NULL == (ptr_node = malloc(sizeof(OSPF))))
    {
	printf("malloc memory failed\n");
	return 0;
    }

    ptr_node->cnt = 0;
    ptr = ptr_node;
    printList(ptr);

    /* add test */
    if(NULL == (ptr_node = ptr_node_del = malloc(sizeof(OSPF))))
    {
	printf("malloc memory failed\n");
	return 0;
    }

    ptr_node->cnt = 1;
    ospf_add_node_to_end_of_list((OSPF_GENERIC_NODE *)ptr_node,(OSPF_GENERIC_NODE *)ptr);
    printList(ptr);

    /* add another */
    if(NULL == (ptr_node = malloc(sizeof(OSPF))))
    {
	printf("malloc memory failed\n");
	return 0;
    }

    ptr_node->cnt = 2;
    ospf_add_node_to_end_of_list((OSPF_GENERIC_NODE *)ptr_node,(OSPF_GENERIC_NODE *)ptr);
    printList(ptr);

    /* delete test */
    ospf_remove_node_from_list((OSPF_GENERIC_NODE **)& ptr,(OSPF_GENERIC_NODE *)ptr_node_del);
    free(ptr_node_del);
    ptr_node_del = NULL;
    printList(ptr);

    /* delete the first node test */
    /* the first node of the list is deleted,ptr is pointed to another head address of the list.
     * at this moment,we lost the address of the first node we deleted,so how to free this node ? */
    /*
    ospf_remove_node_from_list((OSPF_GENERIC_NODE **)& ptr,(OSPF_GENERIC_NODE *)ptr);
    */

    /* just the resean above,we should rewrite the code as below */
    ptr_node_del = ptr;
    ospf_remove_node_from_list((OSPF_GENERIC_NODE **)& ptr,(OSPF_GENERIC_NODE *)ptr_node_del);
    free(ptr_node_del);
    ptr_node_del = NULL;
    printList(ptr);

    /* free the all list */
    ospf_free_entire_list((OSPF_GENERIC_NODE *)ptr);
    ptr = NULL;
    printList(ptr);


    return 0;
}