欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 运维知识 > linux >内容正文

linux

第六天2017/04/11(2:Linux内核链表Demo、顺序表、链表的开发与设计)

发布时间:2025/3/21 linux 50 豆豆
生活随笔 收集整理的这篇文章主要介绍了 第六天2017/04/11(2:Linux内核链表Demo、顺序表、链表的开发与设计) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.
//结构体相关的高级话题#include "stdio.h" #include "stdlib.h" #include "string.h" //定义一个结构体,就相当于各个变量的偏移量也定下来了 struct student {char name[32]; //32个字节int age; //4个字节char *na; //4个字节 };int main() {struct student s = {"Mr.right" , 24 , "Victory"};struct student *p = &s;p = p+1;p = 0; //p = p - p; //此时 p 相当于 ((struct student *)0)int i = (int )(&(p->name)); //0 int i = (int)(&(((struct student *)0)->name))int j = (int )(&(p->age)); //32 int j = (int)(&(((struct student *)0)->age))int k = (int )(&(p->na)); //36 int k = (int)(&(((struct student *)0)->na))int m = (int)&(((struct student *)0)->name);//把0地址空间进行类型转换,转换为struct student *的结构体指针;此处 //再指向结构体中的age; 此处->是一个寻址操作,就是计算age的地址在哪里,没有往age所指向的内存空间读写数据//寻址操作对CPU来讲,只不过是一个+-*/操作 //再取地址 ; //在把地址转换成十进制 } ==================================================================================//【疑问】为什么讲上面的知识:(int)&(((struct student *)0)->age)? //【答】是为了引出“Linux内核链表了解”!Linux内核链表了解: //不是链表包含业务结点 //而是业务结点包含链表//如何从链表结点的位置找到业务结点的位置呢?#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER) //求出MEMBER相对于TYPE结构体的偏移量offset#define container_of(ptr,type,member) (type*)((char*)ptr - offsetof(type,member)) //求整个结构体的偏移量

下图是Linux内核链表的示意图:可以通过链表结点,根据偏移量offset找到
业务结点的起始地址,对业务结点进行操作。

============================================================================

上述图简单介绍了公司的业务数据的设计,代码如下:
实现:让业务结点和链表结点进行有效的分离

#include<iostream> using namespace std;struct List //链表结点 {struct List *next; };struct student //业务结点(中有链表结点) {//数据元素int age;char name[100];//链表结点struct List node; };void insert_node(struct List *pNew,struct List *pHead) //插入链表结点 //注解:不用插入业务结点,实质上只要插入链表结点就可以(因为可以通过链表结点找到业务结点,并对业务结点进行访问) {pNew->next = pHead->next; //此时用的是头插法,打印时,输出结果是逆序的pHead->next = pNew; }void printf_age(struct List *pHead) //打印业务结点 //就像上面说的那样,遍历链表结点,通过链表结点找到业务结点的入口,并对业务结点的数据元素进行访问 {//计算偏移量int offset = (int)&(((struct student*)0)->node);//找到每一个结点的指针struct List *pCur = pHead->next;while(pCur){struct student* pCur_stu = (struct student*)((char*)pCur - offset);cout<<pCur_stu->age<<endl;pCur = pCur->next;} } int main() {struct List pHead; //定义一个链表头结点pHead.next = NULL;struct student a,b,c,d;a.age = 20;b.age = 21;c.age = 22;d.age = 23;insert_node(&a.node,&pHead); //把链表结点插入到链表结点的头结点上insert_node(&b.node,&pHead);insert_node(&c.node,&pHead);insert_node(&d.node,&pHead);printf_age(&pHead); //打印链表结点return 0; }

实质上可以进行“投机取巧,即永远把链表结点放在业务结点的第一个位置,此时:链表结点相对于业务结点的偏移量offset为0.

struct List //链表结点 {struct List *next; };struct student //业务结点(中有链表结点) {//链表结点struct List node;//数据元素int age;char name[100]; }; 1、企业级财富库线性表之单链表开发和设计】 //linklist.h函数声明 #ifndef _MYLINKLIST_H_ #define _MYLINKLIST_H_typedef void LinkList;typedef struct _tag_LinkListNode {struct _tag_LinkListNode* next; }LinkListNode;LinkList* LinkList_Create(); void LinkList_Destroy(LinkList* list); void LinkList_Clear(LinkList* list); int LinkList_Length(LinkList* list); int LinkList_Insert(LinkList* list, LinkListNode* node, int pos); LinkListNode* LinkList_Get(LinkList* list, int pos); LinkListNode* LinkList_Delete(LinkList* list, int pos); #endif ========================================================================= //linklist.cpp函数实现 #include "stdlib.h" #include "stdio.h" #include "string.h"#include "linklist.h"typedef struct _tag_LinkList {LinkListNode header;int length; }TLinkList;LinkList* LinkList_Create() {TLinkList *tList = (TLinkList *)malloc(sizeof(TLinkList));if (tList == NULL){return NULL;}tList->header.next = NULL;tList->length = 0;return tList; }void LinkList_Destroy(LinkList* list) {if (list != NULL){free(list);}return ; }void LinkList_Clear(LinkList* list) {TLinkList *tList = (TLinkList *)list;if (tList == NULL){return ;}tList->length = 0;tList->header.next = NULL;return ; }int LinkList_Length(LinkList* list) {TLinkList *tList = (TLinkList *)list;if (tList == NULL){return -1;}return tList->length; }int LinkList_Insert(LinkList* list, LinkListNode* pNew, int pos) {//将业务结点s中的s.node元素插入到单链表中int i = 0;TLinkList *tList = (TLinkList *)list;LinkListNode *current = NULL;if (tList == NULL || pNew == NULL || pos<0){return -1;}current = &tList->header; //环境初始化for (i=0; (i<pos)&&current->next!=NULL; i++ ) //寻找插入位置{current = current->next;} //插入新结点pNewpNew->next = current->next;current->next = pNew;tList->length ++;return 0; }LinkListNode* LinkList_Get(LinkList* list, int pos) {int i = 0;TLinkList *tList = (TLinkList *)list;LinkListNode *current = NULL;LinkListNode *ret = NULL;if (list==NULL || pos<0 || pos>=tList->length){return NULL;}current = &tList->header;for (i=0; i<pos; i++){current = current->next;}ret = current->next;return ret; }LinkListNode* LinkList_Delete(LinkList* list, int pos) {int i = 0;TLinkList *tList = (TLinkList *)list;LinkListNode *current = NULL;LinkListNode *ret = NULL;if (list==NULL || pos<0 || pos>=tList->length){return NULL;}//没有初始化环境current = &tList->header;for (i=0; i<pos; i++){current = current->next;}ret = current->next;current->next = ret->next;tList->length --;return ret; } ========================================================================= //main.cpp测试程序 #include "linklist.h" #include <iostream> using namespace std;struct Student {LinkListNode node; //Linux内核原理:业务结点中有链表结点char name[100];int age; };void print_LinkList(void* list) //遍历打印链表 {for (int i=0; i<LinkList_Length(list); i++){struct Student *tmp = (struct Student*)LinkList_Get(list, i);printf("name: %s , age: %d\n", tmp->name,tmp->age);} }int main() {Student s1; strcpy(s1.name,"Tom"); s1.age = 20;Student s2; strcpy(s2.name,"Tim"); s2.age = 21;Student s3; strcpy(s3.name,"Kim"); s3.age = 22;LinkList* list = list = LinkList_Create(); /************************************************************************/ //case1:LinkList_Insert(list,&s1.node,0); //把s1中的链表结点s1.node结点插入到链表listLinkList_Insert(list,&s2.node,0); //把s2中的链表结点s2.node结点插入到链表listLinkList_Insert(list,&s3.node,0); //把s3中的链表结点s3.node结点插入到链表list//LinkList_Insert(list,(LinkListNode*)(&s1.node),0);//LinkList_Insert(list,(LinkListNode*)(&s2.node),0);//LinkList_Insert(list,(LinkListNode*)(&s3.node),0); //case2://LinkList_Insert(list,(LinkListNode*)(&s1),0);//LinkList_Insert(list,(LinkListNode*)(&s2),0);//LinkList_Insert(list,(LinkListNode*)(&s3),0);print_LinkList(list); /************************************************************************/cout<<"删除结点"<<endl;LinkList_Delete(list,1);print_LinkList(list);} /************************************************************************/ /************************************************************************/2、企业级财富库线性表之顺序存储开发和设计】 【核心问题】业务数据 和 链表算法(底层库)是如何分离的? //seqlist.h:函数声明 #ifndef __MY_SEQLIST_H__ #define __MY_SEQLIST_H__typedef void SeqList; typedef void SeqListNode;//疑问:为什么传入的形参类型、返回的类型为void* ? //答:底层不想让别人知道我是什么结构的,也没有必要让别人知道SeqList* SeqList_Create(int capacity); //创建容量为capacity的顺序线性表 void SeqList_Destroy(SeqList* list); //释放线性表list void SeqList_Clear(SeqList* list); //清空线性表list int SeqList_Length(SeqList* list); int SeqList_Capacity(SeqList* list); int SeqList_Insert(SeqList* list, SeqListNode* node, int pos); SeqListNode* SeqList_Get(SeqList* list, int pos); SeqListNode* SeqList_Delete(SeqList* list, int pos); int for_each(void (*CALLBACK_print)(void*),void* list); //回调函数循环遍历 #endif //void* SeqList_Create(int capacity); //void SeqList_Destroy(void* list); //void SeqList_Clear(void* list); //int SeqList_Length(void* list); //int SeqList_Capacity(void* list); //int SeqList_Insert(void* list, void* node, int pos); //void* SeqList_Get(void* list, int pos); //void* SeqList_Delete(void* list, int pos);=============================================================================== //seqlist.cpp:函数实现 #include "seqlist.h" #include "stdlib.h" #include "stdio.h" #include "string.h"typedef struct _tag_SeqList {int capacity; //sizeof(数组),数组实际占有的内存大小int length; //strlen(数组),数组中存放着几个数据unsigned int *node ; //数组的头指针 }TSeqList;//typdef的意思 把void 重新命名成SeqList/* void * SeqList_Create2(int capacity) //分配两次内存,恶心! {TSeqList *ret = NULL;ret = (TSeqList *)malloc(sizeof(TSeqList));if (ret == NULL){return NULL;}ret->capacity = capacity;ret->node = (unsigned int *)malloc(sizeof(unsigned int ) * capacity);if (ret->node == NULL){return NULL;}ret->length = 0;return ret; } */void * SeqList_Create(int capacity) //创建一个长度为capacity的数组,数组的数据类型是unsigned int {TSeqList *ret = NULL;if (capacity <= 0){return NULL;}ret = (TSeqList *)malloc(sizeof(TSeqList) + sizeof(unsigned int ) * capacity );//一次性全部分配内存if (ret == NULL){return NULL;}ret->capacity = capacity; ret->length = 0;ret->node = (unsigned int *)(ret + 1);return ret; }void SeqList_Destroy(SeqList* list) {if (list == NULL){return ;}free(list);return ; }void SeqList_Clear(SeqList* list) //不是释放内存,是直接把长度设为0 {TSeqList *tlist = NULL;if (list == NULL){return ;}tlist = (TSeqList *)list;tlist->length = 0;//直接把长度设为0return ; }int SeqList_Length(SeqList* list) {TSeqList *tlist = (TSeqList *)list;if (list == NULL){return -1;}return tlist->length; }int SeqList_Capacity(SeqList* list) {TSeqList *tlist = (TSeqList *)list;if (list == NULL){return -1;}return tlist->capacity; } //注解:实际位置和下标位置总是相差1 int SeqList_Insert(SeqList* list, SeqListNode* node, int pos) //插入位置:length+1>=pos>=1 {if(list == NULL||node == NULL)return -1;TSeqList *tlist = (TSeqList*)list; //capacity空间不够if(tlist->length >= tlist->capacity) return -2; //容错 //插入位置length+1>=pos>=1if(pos > tlist->length+1){pos = tlist->length;}if(pos < 1){pos = 1;} //插入操作int i = tlist->length-1; //最后一个有效元素的位置while(i>=pos-1) //循环后移{tlist->node[i+1] = tlist->node[i];i--;}tlist->node[pos-1] = (unsigned int)node; //插入tlist->length++;return 0; }SeqListNode* SeqList_Get(SeqList* list, int pos) //查找位置:length>=pos>=1 {TSeqList *tlist = (TSeqList *)list;if (list== NULL || pos<1 || pos>tlist->length){return NULL;}return (SeqListNode*)tlist->node[pos-1]; }SeqListNode* SeqList_Delete(SeqList* list, int pos) //删除位置:length>=pos>=1 {int i = 0;TSeqList *tlist = (TSeqList *)list;SeqListNode* ret = NULL;if (list == NULL || pos<1 || pos>tlist->length){return NULL;} //缓存要删除的结点ret = (SeqListNode*)tlist->node[pos-1]; //对链表元素值循环前移i = pos-1;while(i<=tlist->length-1){tlist->node[i] = tlist->node[i+1];i++;} //删除后,长度-1tlist->length --;return ret; }int for_each(void (*CALLBACK_print)(void*),void* list) {if(list == NULL)return -1;(*CALLBACK_print)(list);return 0; } =============================================================================== //线性表顺序存储测试.cpp:测试代码 #include "seqlist.h" #include "stdlib.h" #include "stdio.h" #include "string.h"typedef struct _Teacher //业务结点 {char name[64];int age ; }Teacher;void CALLBACK_print(void* list) //循环遍历的回调函数 {printf("循环遍历:\n");for (int i=1; i<=SeqList_Length(list); i++){Teacher *tmp = (Teacher *)SeqList_Get(list, i);printf("name:%s , age:%d \n", tmp->name,tmp->age);} }void main() { //创建业务数据,并初始化Teacher t1 = {"Kobe",20};Teacher t2 = {"James",19};Teacher t3 = {"Curry",16}; //环境准备int ret = 0, i = 0;SeqList* list = NULL; //创建线性表list = SeqList_Create(10);//仔细思考:业务数据 和 链表算法(底层库)是如何分离的。。。。。。//业务数据结点的管理(内存的生命周期)甩给了上层应用(业务模型) //插入ret = SeqList_Insert(list, (SeqListNode*)&t1, 1);ret = SeqList_Insert(list, (SeqListNode*)&t2, 1);ret = SeqList_Insert(list, (SeqListNode*)&t3, 1); //循环遍历for_each(CALLBACK_print,list); //删除 SeqList_Delete(list, 2);for_each(CALLBACK_print,list); //销毁线性表SeqList_Destroy(list);system("pause"); }

总结

以上是生活随笔为你收集整理的第六天2017/04/11(2:Linux内核链表Demo、顺序表、链表的开发与设计)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。