可接受任意类型的数据的C语言链表
今天在宣讲会上讲了一下我所写的那个可以接收任意类型的参数类型的链表,感觉还是没有讲清楚,再次整理一下 ,同样的道理我们可以构造出其它的可以接受任意数据类型的结构,如:可接收任意数据类型的栈,可接收任意数据类型的队列,可接收任意数据类型的树·················
现在我们要在链表中存储任意类型的数据(也就是说数据所占字节数是在使用链表的时候确定),既然要能存储任意类型的数据,那么我们的链表的节点和链表的定义就要做一些修改了。
下图是节点和链表的定义,data是一个ElemType类型的数据,而ElemType是被我们定义成了一个void *,也就是一个空指针。head和tail都是一个ChainNode类型的指针,作为链表的头结点和尾巴节点,头结点本书的数据域是不存放数据的。Nodesize表示要存储的数据类型的字节大小。
这个时候data这个指针才是真正指向了我们存放在链表里面的数据,
实现代码的讲解:
首先我们初始化一个链表mylist
myElemType是我们自己定义的任意类型的数据
List * mylist;
mylist = CreateList( sizeof(myElemType) );
然后我们想要在链表上面附加myElemType类型的数据,可以直接调用ListAppend(mylist ,a);
//a是一个myElemType类型数据,
这里的ListAppend第二个参数之所以能接受任意参数是因为它的声明形式是
int ListAppend(List * plist,...)
我们在声明的时候已经指示了,除第一个参数外,后面的参数可以是任意类型的,
下面分析一下在执行这条语句执行后参数在栈空间里面的存储形式,首先入栈的是plist这个指针,存储这个指针位置是下面就是我们1个myElemType类型的数据(大小为Nodesize,初始化链表的时候确定)。
下面以ListAppend为列子,分析的思想:
已经知道了节点的内存示意(图一)和调用ListAppend之后栈空间的内存分布(图二)
图一 图二
那么首先我们就是要为节点本身分配一款内存(存储两个指针next和data),然后我们还要为data这个指针分配额一块内存,用来存储数据,也就是上面图一蓝色的部分。然后再将此时已经在栈里面的数据通过memcpy函数拷贝到节点指针data所指向的内存(图中的三个红色箭头)。关于memcpy函数:
void *memcpy( void *dest, const void *src, size_tcount);
就是从指针src所指向地址拷贝count个字节到另一个指针所dest指向的地址,拷贝个数由参数size确定,我们这里当然可以传入我们在初始化链表的时候给予的数据字节大小的plist->Nodesize;
实际操作如下的:
ListAppend函数代码:
int ListAppend(List * plist,...)
{
ChainNode * newpt = 0;
void * data;
void * pos;
pos = &plist + 1; //这个时候pos指向的实际就是在栈里面的一个myElemType类型数据的首地址
if( !(plist && plist->head) ) return 0; //防止指针为空
data = (void *)malloc(plist->Nodesize); //为直接的数据域指针分配空间,大小是(当前Nodesize)
if( !data ) return 0; //防止指针为空
memcpy(data,pos,plist->Nodesize); //将栈里面的一个myElemType类型数据拷贝到data指针所指向的内存
newpt = NewChainNode(data);
if( !newpt ) return 0; //防止指针为空
plist->tail->next = newpt; //将新建的节点添加到链表最后面
plist->tail = newpt;
return 1;
}
代码如下
typedef void * ElemType; typedef struct node { ElemType data; struct node * next; }ChainNode; typedef struct { ChainNode *head; int Nodesize; ChainNode *tail; }List; List * CreateList(int); /* 创建链表 */ void DestoryList(List*); /* 销毁链表 */ void ClearList(List*); /* 清空链表 */ int ListAppend(List*,...); /* 追加元素 */ int ListInsert(List*,int,...); /* 加入元素 */ int ListDelete(List *,int); /* 删除第几个元素 */ int GetElem(List*,int,ElemType *); /* 取得第几个元素的值用第三个参数返回 */ ChainNode * GetAddr(List *, int); /* 取得编号为N的元素所在地址 */ int TraverseList(List*,int (*)(ElemType )); /* 遍历访问,反问某个节点元素用函数处理 */ ChainNode * NewChainNode( ElemType); List *CreateList(int size ) { List * pt = 0; ElemType data = 0; pt=(List*)malloc( sizeof(List) ); if( !pt ) return 0; pt->head = NewChainNode(data ); if( ! pt->head ) { free(pt); return 0; } pt->Nodesize = size; pt->tail = pt->head; return pt; } /*==================*/ void DestoryList(List * plist) { ClearList(plist); free(plist->head); plist->head = 0; free(plist); plist = 0; } /*==================*/ int ListAppend(List * plist,...) { ChainNode * newpt = 0; void * data; void * pos; pos = &plist + 1; if( !(plist && plist->head) ) return 0; data = (void *)malloc(plist->Nodesize); if( !data ) return 0; memcpy(data,pos,plist->Nodesize); newpt = NewChainNode(data); if( !newpt ) return 0; plist->tail->next = newpt; plist->tail = newpt; return 1; } /*==================*/ int ListInsert(List * plist, int n ,...) { ChainNode * pt = 0; ChainNode * newpt = 0; void * data; void *pos = &plist + 2; pt = GetAddr( plist, n-1 ); if( !(pt) ) return 0; data = (void*)malloc(plist->Nodesize); if( !data ) return 0; memcpy(data,pos,plist->Nodesize); newpt = NewChainNode(data); if( !newpt ) return 0; if ( pt->next == plist->tail ) plist->tail = newpt; newpt->next = pt->next; pt->next = newpt; return 1; } /*==================*/ int GetElem(List * plist,int n,ElemType *data) { ChainNode * pt = 0; if( !data ) return 0; pt = GetAddr(plist,n); if( ! pt ) return 0; memcpy(data, pt->data ,plist->Nodesize); return 1; } /*==================*/ int TraverseList(List* plist,int (*f)(ElemType )) { ChainNode * pt = 0; int a=0; /**/ if( !(plist && plist->head) ) return 0; for( a = 0 ,pt = plist->head->next; pt ; pt = pt->next ) { if( ! f( (pt->data)) ) return a+1; a++; } return 0; } /*==================*/ void ClearList(List * plist) { while ( ListDelete(plist,1) ); } /*==================*/ int ListDelete( List * plist, int n ) { ChainNode * pt =0; ChainNode * pf=0; if( !plist->head->next ) return 0; pt = GetAddr( plist,n-1 ); if ( pt->next == plist->tail ) plist->tail = pt; if( !(pt && pt->next )) return 0; pf = pt->next; pt->next = pt->next->next; free(pf->data); free(pf); return 1; } ChainNode * GetAddr(List * plist,int n) { ChainNode * pt = 0; int a = 0; if( n < 0) return 0; pt = plist->head; while( pt && a < n ) { pt = pt->next; a++; } return pt; } /*==================*/ ChainNode * NewChainNode(ElemType data) { ChainNode * pChain=0; pChain = ( ChainNode * )malloc( sizeof(ChainNode) ); if( ! pChain ) return 0; pChain->data=data; pChain->next=0; return pChain; }
uselist.c
#include "list.h"
/*提供两种数据测试*/
typedef struct {char ch ; int id; char name[10]; int r;} myElemType;
/*
typedef char myElemType;
*/
myElemType a[20] ={{'a',1,"niei",2},{'b',2,"aini",2},{'c',3,"love",2},{'d',4,"jack",2},{'e',5,"alice",2},{'f',6,"ben",2},{'g',7,"carlo",2},{'h',8,"mason",2}};
/*
myElemType a[20]="Hello world!";
*/
void showList(List* );
int putElem( myElemType *);
void main()
{
List * mylist;
int n=0;
myElemType data;
myElemType data2;
myElemType* pdata;
mylist = CreateList( sizeof(myElemType) );
if( ! mylist)
{
printf("error");
return;
}
for( n = 0 ;n < 8 ;n++)
ListAppend(mylist ,a[n]);
showList( mylist);
data.ch = '*';
data.id = 8;
strcpy(data.name , "1223");
data.r = 2;
/* a[0]='E';
a[1]='r';
a[2]='r';
a[3]='o';
a[4]='r';
*/ ListInsert(mylist,1,data);
showList( mylist);
/**/ data2.ch = 'A';
data2.id = 54;
strcpy(data2.name , "bill");
data2.r = 4;
ListInsert(mylist,7,data2);
showList( mylist);
ListDelete(mylist,7);
showList( mylist);
ListDelete(mylist,1);
showList( mylist);
if (GetElem(mylist,5,&data2) )
/* printf("[%c %d %s %d] ",data2.ch,data2.id,data2.name,data2.r);*/
printf("[%c]",data2);
ClearList(mylist);
showList( mylist);
DestoryList(mylist);
mylist = 0;
showList( mylist);
}
/*==================*/
void showList(List* plist)
{
if( !plist )
return;
TraverseList(plist,(int(*)(void *))putElem);
printf("\n");
}
/*输出字符*/
/*
int putElem(myElemType *data)
{
if( ! ( data) )
return 0;
printf("%c",*data);
return 1;
}
*/
/*输出结构体*/
/**/
int putElem(myElemType *data)
{
if( ! ( data) )
return 0;
printf("[%c %d %s %d] ",(data)->ch,(data)->id,(data)->name,(data)->r);
return 1;
}
最后的运行结果,一个[ ] 表示一个结构体所有成员