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