//结构体相关的高级话题
#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); //释放线性表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;//直接把长度设为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;
}
//注解:实际位置和下标位置总是相差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>=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");
}