第六天2017/04/11(2:Linux内核链表Demo、顺序表、链表的开发与设计)
来源:互联网 发布:linux assert函数 编辑:程序博客网 时间:2024/06/10 22:48
//结构体相关的高级话题#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)&¤t->next!=NULL; i++ ) //寻找插入位置 { current = current->next; }//插入新结点pNew pNew->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结点插入到链表list LinkList_Insert(list,&s2.node,0); //把s2中的链表结点s2.node结点插入到链表list LinkList_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); //释放线性表listvoid SeqList_Clear(SeqList* list); //清空线性表listint 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;//直接把长度设为0 return ;}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;}//注解:实际位置和下标位置总是相差1int 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>=1 if(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++; }//删除后,长度-1 tlist->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");}
1 0
- 第六天2017/04/11(2:Linux内核链表Demo、顺序表、链表的开发与设计)
- linux内核设计与实现(第六章)----内核数据结构
- 《Linux内核设计与实现》读书笔记(六)- 内核数据结构之链表与队列
- linux内核数据结构-顺序存储链表(1)
- Linux 内核开发 - 内核链表
- 内核驱动开发第四天linux内核链表
- [笔记]《Linux内核设计与实现》第六章内核数据结构
- Linux内核设计与实现 读书笔记(2)内核开发的准备
- 《Linux内核设计与实现》读书笔记(二)- 内核开发的准备
- Linux内核设计与实现 (二) 内核开发的准备
- 《Linux内核设计与实现》读书笔记(二)- 内核开发的准备
- 《Linux内核设计与实现》读书笔记(二)- 内核开发的准备
- <<Linux内核设计与实现>>读书笔记(二)-内核开发的准备
- 《Linux内核设计与实现》读书笔记(二)- 内核开发的准备
- 《Linux内核设计与实现》读书笔记(二)- 内核开发的准备
- 《Linux内核设计与实现》读书笔记(二)- 内核开发的准备
- 《linux内核设计与实现》阅读笔记 第六章 下半部和推后执行的工作
- linux驱动开发--内核链表
- org.apache.catalina.core.ContainerBase.addChildInternal ContainerBase.addChild: start: org.apache.
- 实现哈夫曼树
- Redis消息通知系统的实现
- 关于matplotlib的twinx()的使用
- POJ1724 Dij队列优化邻接表
- 第六天2017/04/11(2:Linux内核链表Demo、顺序表、链表的开发与设计)
- 24点(随机输出四个数,输出所有结果为24的等式)
- HDU2544 最短路
- 子类可以继承到父类上的注解吗--有结论了
- java生成c++头文件
- 自定义SwipeLayout侧拉删除控件
- swustoj似曾相识(0314)
- 防止SQL注入的函数?
- 树莓派开发板Android Things镜像烧录