第六天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)&&current->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