C语言通用数据类型链表的实现,(数据域为指针,可指向任意类型数据)
来源:互联网 发布:寝室管理系统数据库 编辑:程序博客网 时间:2024/05/01 09:23
可接受任意类型的数据的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;}
最后的运行结果,一个[ ] 表示一个结构体所有成员
- C语言通用数据类型链表的实现,(数据域为指针,可指向任意类型数据)
- C语言通用数据类型链表的实现,(数据域为指针,可指向任意类型数据)
- 可接受任意类型数据的C语言链表
- 指向结构体类型数据的指针
- 指向结构体类型数据的指针
- 指向结构体类型数据的指针
- 指向结构体类型数据的指针
- 指向结构体类型数据的指针
- 指向结构体类型数据的指针
- C语言通用数据类型链表的实现
- 数据共享+指向自身类型的指针+智能指针
- 【C语言】使用指向指针数据的指针变量,输出一组字符串
- osg源码中的ref_ptr operator unspecified_bool_type() 指向类数据成员的指针&类转化为另一类型(如自定义的C类转化为int)
- 指向指针数据的指针
- java实现输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head
- C语言二级指针(指向指针的指针)
- C语言指针(二)指向指针的指针
- 98 C语言二级指针(指向指针的指针)
- 编程珠玑(性能篇)
- 职工管理系统
- 你真的以为你的成绩是由你自己的努力换来的?
- Parameter DIRECT: Conventional Path Export Versus Direct Path Export [ID 155477.1]引用
- vc中没有opengl库文件的加载方法
- C语言通用数据类型链表的实现,(数据域为指针,可指向任意类型数据)
- NO_MORE_IRP_STACK_LOCATIONS
- 中国大陆低工资高物价的原因
- unity3D开发android初步篇(86)
- javascript window.location对象
- java中的List新发现
- C语言入门教程 (五) 编写第一个C语言程序
- linux 中解析命令行参数 (getopt_long用法)
- 一句代码解决全选问题