单向链表删除并清空操作 注意

    在之前的文章《深入理解Linux内核之链表 list.h 功能实现原理、接口说明及示例代码》中详细的分析了链表的各种操作,我们经常使用的操作是“初始化”、“ 添加节点”、“遍历”、“删除”,对于链表节点的删除,使用的相对少,而且由于 删除操作的 宏函数 定义的复杂,容易混淆,本文基于此,对 链表的删除清空做下备忘录。

以单向链表结构 为例,用到的宏函数有2个,分别为:

/*
 * Iterate over list of given type safe against removal of list entry.
 *
 * @param[in]   queue   the head for your list.
 * @param[in]   tmp     the type * to use as a temp.
 * @param[in]   node    the type * to use as a loop cursor.
 * @param[in]   type    the type of the struct this is embedded in.
 * @param[in]   member  the name of the slist_t within the struct.
 */
#define slist_for_each_entry_safe(queue, tmp, node, type, member) \
    for (node = container_of((queue)->next, type, member),    \
         tmp = (queue)->next ? (queue)->next->next : NULL;        \
         &node->member;                                           \
         node = container_of(tmp, type, member), tmp = tmp ? tmp->next : tmp)

/* 节点删除 */
static inline void slist_del(slist_t *node, slist_t *head)
{
    while (head->next) {
        if (head->next == node) {
            head->next = node->next;
            break;
        }
 
        head = head->next;
    }
}

   其中 slist_for_each_entry_safe 中包含了 “safe” ,含义是 “安全”, 专用于 链表删除 的 遍历动作。这个函数的参数类型容易有歧义,这里我们做下 解释:

/*
 * Iterate over list of given type safe against removal of list entry.
 *
 * @param[in]   queue   链表 头 head 指针, 是一个指针
 * @param[in]   tmp     struct slist_s * 类型的 临时指针变量
 * @param[in]   node    我们自己的 链表结构 节点 指针,.
 * @param[in]   type    我们自己定义的 链表结构体类型, 必须要包含 struct slist_s list 成员.
 * @param[in]   member  我们自己定义的 链表结构体类型 中的 list 成员
 */
#define slist_for_each_entry_safe(queue, tmp, node, type, member)

  而 slist_del(slist_t *node, slist_t *head) 的参数解释如下:

/*
 * Iterate over list of given type safe against removal of list entry.
 *
 * @param[in]   node    struct slist_s * 类型的 节点变量,是一个指针
 * @param[in]   head    链表 头 head 指针, 是一个指针
 */

static inline void slist_del(slist_t *node, slist_t *head)

  删除并释放 所有链表节点的 程序案例:

/* 自定义的 链表结构体*/
typedef struct{
  int id; 
  int a;
  int b;
  struct slist_s list;
} usr_list_info_t;


/*--------------- 删除整个链表的伪操作 ---------------*/
struct slist_s *head = get_usr_list_head();
struct slist_s *tmp = NULL;
usr_list_info_t *node = NULL;
 
slist_for_each_entry_safe(head, tmp, node, usr_list_info_t, list){
    slist_del(&(node->list), head);
    free(node);
}

     如果想删除某一个节点,也是上面的套路,只不过在遍历所有的节点同时,判断当前节点是否是我们想要删除的节点,如果是,则删除,不是则接着遍历。

你可能感兴趣的:(Linux,C/C++)