双向链表的结构体如下:
typedef struct _dbLinkList{
datetype data;
_dbLinkList* pre;
_dbLinkList* next;
}dbLinkList,dbLinkNode;
其中的数据类型datatype根据实际情况,或者是普通的数据类型或者是自定义的结构体类型,这样datatpye 的不同,每种数据类型都要写相应的创、删、查、改、消函数,实际开发中会用到多个链表结构,这样做的工作量大,有没有一种比较轻便的方法,减少函数的开发,提高代码的可重用性呢?有,那就是“双向链表挂件”,将data从双向链表中剥离出来,其结构如下:
typedef struct _dbLinkList{
_dbLinkList* pre;
_dbLinkList* next;
}dbLinkList,dbLinkNode;
同时根据实际需求,增加结构体定义
typede struct _connecTimeOut{
int fd;
time_t timeout;
dbLinkList node;
}
结构体挂件定义好以后,有一个比较奇妙的方法通过双向链表的结点node,可以访问fd和timeout,这个函数就是 offsetof,获取结构体分量和对应分量的偏移量,这样就可以通过node的地址减去偏移量就可以获得connecTimeOut结构体的地址,进而访问对应的分量。不过在中间过程中涉及到强制类型转换。核心代码如下:
dbLinkList* p =&(ct->node);
int off = offsetof(connectTimeOut, node);
connectTimeOut* tmp = (connectTimeOut*)((size_t)p - off);
整个测试代码如下,双向链表的共享结构确实很方便,可以一个双向链表通吃天下。
#include<Windows.h>
#include<string>
#include<iostream>
using namespace std;
typedef struct _dbLinkList {
_dbLinkList* pre;
_dbLinkList* next;
}dbLinkListNode,dbLinkList;
typedef struct _connectTimeOut {
int fd;
time_t timeout;
dbLinkList node;//双向链表的挂件
}connectTimeOut;
typedef struct _STAR {
int x;
int y;
int step;
int color;
int radius;
dbLinkList node;
}STAR;
bool initLinkListConnTimeOut(connectTimeOut* &ct) {
if (!ct) return false;
ct->fd = -1;
ct->timeout = 0;
ct->node.pre = NULL;
ct->node.next = NULL;
return true;
};
bool initLinkListStar(STAR* &star) {
if (!star) return false;
star->x = 0;
star->y = 0;
star->step = 0;
star->radius = 0;
star->color = 0;
star->node.next = NULL;
star->node.pre = NULL;
return true;
}
bool dbLinkListInsertBack(dbLinkList &link, dbLinkList &node) {
dbLinkList* p = &link;
while (p->next != NULL) {
p = p->next;
}
p->next = &node;
node.pre = p;
node.next = NULL;
return true;
};
int main() {
connectTimeOut* ct = NULL;
ct = new connectTimeOut;
STAR* star = NULL;
star = new STAR;
//01 初始化
initLinkListConnTimeOut(ct);
initLinkListStar(star);
//02-添加元素
connectTimeOut* tmp = NULL;
int cout;
std::cout << "通过尾插法将数据插入双向链表中,请输入文件句柄个数:" << std::endl;
cin >> cout;
std::cout << "请依次输入文件句柄:";
for (int i = 0; i < cout; i++) {
tmp = new connectTimeOut;
cin >> tmp->fd;
dbLinkListInsertBack(ct->node,tmp->node);
}
//03-根据链表结点访问文件句柄
dbLinkList* p = &(ct->node);
std::cout << "通过双向链表结点来遍历访问文件句柄!" << std::endl;
while (p->next) {
p = p->next;
int off = offsetof(connectTimeOut, node);
connectTimeOut* tmp =(connectTimeOut*) ((size_t)p - off);
std::cout << tmp->fd<<" "<<p << std::endl;
}
//04--销毁双向链表
std::cout << "销毁双向链表的结点" << std::endl;
p = &(ct->node);
while (p) {
int off = offsetof(connectTimeOut, node);
connectTimeOut* tmp=(connectTimeOut*)((size_t)p - off);
std::cout << tmp->fd << " " << p << std::endl;
p = p->next;
delete tmp;
}
/*connectTimeOut* ct = NULL;
ct = new connectTimeOut;
cout << "请输入一个fd的数据";
cin >> ct->fd;
dbLinkList* p =&(ct->node);
int off = offsetof(connectTimeOut, node);
connectTimeOut* tmp = (connectTimeOut*)((size_t)p - off);
cout<<tmp->fd;*/
system("pause");
return 0;
}