本文是承接上文《C和指针》阅读笔记(11)—单链表数据结构的设计和实现的延续。提供第二种单链表的设计及实现方法。
link.h 详细信息已在注释中说明,仔细分析代码即可。
#ifndef _LINK_H
#define _LINK_H
/*
* 本单链表接口使用宏实现
* 该系列接口的设计与业务完全无关
* 节点内存的分配与释放由调用者负责
* 业务结构和逻辑可在此接口上再次封装
*
*/
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief SL_HEAD
* 定义链表头结构
*
* @param name 链表头结构名,链表头就代表一个链表对象
* @param type 链表节点结构名
*
* @return
*/
#define SL_HEAD(name, type) \
typedef struct \
{ \
type *sl_head; \
} name
/**
* @brief SL_NODE
* 定义匿名节点指针结构体
*
* @param type 链表节点结构名
*
* @return
*/
#define SL_NODE(type) \
struct \
{ \
struct type *sl_next; \
}
/**
* @brief SL_INSERT_HEAD
* 新节点头插入链表
*
* @param link 链表头指针
* @param entry 新节点指针
* @param field 节点成员名
*
* @return
*/
#define SL_INSERT_HEAD(link, entry, field) \
do \
{ \
(entry)->field.sl_next = (link)->sl_head; \
(link)->sl_head = (entry); \
}while(0)
/**
* @brief SL_INSERT_TAIL
* 新节点尾插入链表
*
* @param tail_entry 链表当前尾节点指针
* @param entry 新节点指针
* @param field 节点成员名
*
* @return
*/
#define SL_INSERT_TAIL(tail_entry, entry, field) \
do \
{ \
(entry)->field.sl_next = (tail_entry)->field.sl_next; \
(tail_entry)->field.sl_next = (entry); \
}while(0)
// 获取链表头节点指针
#define SL_FIRST(link) ((link)->sl_head)
// 获取链表尾
#define SL_END(head) NULL
// 获取下一个节点指针
#define SL_NEXT(entry, field) ((entry)->field.sl_next)
// 初始化链表头指针
#define SL_HEAD_INIT(link) \
do{SL_FIRST(link) = SL_END(link);}while(0)
// 遍历链表
#define SL_FOREACH(tmp, link, field) \
for ((tmp) = SL_FIRST(link); (tmp) != SL_END(link); (tmp) = SL_NEXT(tmp, field))
// 移动头节点
#define SL_REMOVE_HEAD(link, field) \
(link)->sl_head = (link)->sl_head->field.sl_next;
#ifdef __cplusplus
}
#endif
#endif //_LINK_H
main.c
#include <stdio.h>
#include <stdlib.h>
#include "link.h"
// 定义一个苹果结构体
typedef struct _apple_s
{
SL_NODE(_apple_s) node;
float price;
char type;
}apple_t;
int test_case1()
{
// 定义apple_link头指针结构体
SL_HEAD(apple_link, apple_t);
// 定义苹果链表
apple_link link_apple;
// 初始化苹果链表
SL_HEAD_INIT(&link_apple);
// 分配节点内存, 分配三个苹果
// 链表宏接口不负责节点内存的分配
apple_t apple1 = {.price = 0.1, .type = 1};
apple_t apple2 = {.price = 0.2, .type = 2};
apple_t apple3 = {.price = 0.3, .type = 3};
// 节点头插入链表
// 将苹果1、苹果2、苹果3依次插入苹果链表
SL_INSERT_HEAD(&link_apple, &apple1, node);
SL_INSERT_HEAD(&link_apple, &apple2, node);
SL_INSERT_HEAD(&link_apple, &apple3, node);
// 遍历链表节点
// 打印链表上的苹果的详细信息
apple_t *p = NULL;
SL_FOREACH(p, &link_apple, node)
printf("price=%f, type=%d\n", p->price, p->type);
return 0;
}
int test_case2()
{
// 定义apple_link头指针结构体
SL_HEAD(apple_link, apple_t);
// 定义链表
apple_link link_apple;
// 初始化链表
SL_HEAD_INIT(&link_apple);
// 分配节点内存
// 链表宏接口不负责节点内存的分配
apple_t apple1 = {.price = 0.1, .type = 1};
apple_t apple2 = {.price = 0.2, .type = 2};
apple_t apple3 = {.price = 0.3, .type = 3};
SL_INSERT_HEAD(&link_apple, &apple1, node);
// 节点尾插入链表
SL_INSERT_TAIL(&apple1, &apple2, node);
SL_INSERT_TAIL(&apple2, &apple3, node);
// 遍历链表节点
apple_t *p = NULL;
SL_FOREACH(p, &link_apple, node)
printf("price=%f, type=%d\n", p->price, p->type);
return 0;
}
int test_case3()
{
// 定义apple_link头指针结构体
SL_HEAD(apple_link, apple_t);
// 定义链表
apple_link link_apple;
// 初始化链表
SL_HEAD_INIT(&link_apple);
// 分配节点内存
// 链表宏接口不负责节点内存的分配
apple_t apple1 = {.price = 0.1, .type = 1};
apple_t apple2 = {.price = 0.2, .type = 2};
apple_t apple3 = {.price = 0.3, .type = 3};
SL_INSERT_HEAD(&link_apple, &apple1, node);
// 节点尾插入链表
SL_INSERT_TAIL(&apple1, &apple2, node);
SL_INSERT_TAIL(&apple2, &apple3, node);
printf("移除头节点前:\n");
// 遍历链表节点
apple_t *p = NULL;
SL_FOREACH(p, &link_apple, node)
printf("price=%f, type=%d\n", p->price, p->type);
// 移除头节点
SL_REMOVE_HEAD(&link_apple, node);
printf("移除头节点后:\n");
p = NULL;
SL_FOREACH(p, &link_apple, node)
printf("price=%f, type=%d\n", p->price, p->type);
return 0;
}
int main(int argc, char** argv)
{
int n = atoi(argv[1]);
switch(n)
{
case 1:
test_case1();
break;
case 2:
test_case2();
break;
case 3:
test_case3();
break;
default:
printf("not support operate\n");
}
return 0;
}