起因
c++里面有模板,可以很容易实现链表,栈等数据结构。可我用的是C语言,每次用到链表,都要重新写一次那几个函数,很麻烦,今天突然想到了之前看的一本书,于是想到了解决办法,其实别人早就做了,只是我啥也不会,到现在才明白。如下,链表节点存储一个指针,指向存储元素的副本。
typedef struct LIST
{
void *pval; //指向元素的指针,以此可以存储任意类型
struct LIST *next; //不说了,你也懂
}LIST;
接下来,就是实现了
写在前面,我发现如果要想在函数实参列表得到返回值,那么就需要传递这个形参的指针,这个是我在下面查找元素的函数实现过程中醒悟的,虽然晚了点。
初始化
LIST* LIST_Init(void)
{
LIST *head;
head = (LIST*)malloc(sizeof(LIST));
head->next = NULL; //初始化的值必须是 NULL
head->pval = NULL;
return head;
}
添加元素
//正确执行,返回0,否则返回错误代码,
//@param ArrElement:需要添加的元素数组的地址
//@param ElemenNum:需要添加的元素数组的长度
//@param ElementSize:需要添加的元素的大小,以字节为单位
int LIST_add(LIST *head,void *ArrElement,int NumOfArrElement,int ElementSize)
{
if(head==NULL)
return ptr_null; //ERROR_CODE类型,强制转换为整形输出了
int i=0;
LIST *temp,*pre=head;
void *ptr_val=NULL;
while(pre->next) //遍历到 LIST 的尾节点
{
pre = pre->next;
}
for(i=0;i<NumOfArrElement;i++)
{
temp = (LIST*)malloc(sizeof(LIST)); //分配LIST节点的内存
if(temp==NULL) //如果没有申请到内存,直接返回错误代码,结束函数
return mem_NotEnough;
temp->next = NULL;
temp->pval = NULL; //初始化的值必须是 NULL
pre->next = temp;
pre = temp; //将指针后移到新分配的节点
ptr_val = malloc(ElementSize); //分配存储元素的内存
if(ptr_val==NULL)
return mem_NotEnough;
memcpy(ptr_val,ArrElement+i*ElementSize,ElementSize); //将元素存储到分配的内存中
temp->pval = ptr_val;
}
return 0;
}
查找元素
//@param List ptr_ret:返回的链表节点的指针,注意是二级指针,
//如果找到,返回0,没有返回出错代码
//@param void *Element :要寻找的元素的地址,考虑到以后会寻找结构体,使用地址会很方便
//@param int ElemenSize:元素的大小,sizeof(ElementType),以字节计算
//@param List **ptr_ret:返回的链表节点的指针, 注意是二级指针,
int LIST_GetElement(LIST *head,void *Element,int ElementSize,LIST **ptr_ret)
{
if(head==NULL)
return ptr_null; //ERROR_CODE类型,强制转换为整形输出了
LIST *temp=head->next;
while(temp)
{
if(memcmp(temp->pval,Element,ElementSize)) //如果不相等,下一个
{
temp = temp->next;
}
else
{
*ptr_ret = temp;
return 0; //如果找到了,直接返回,
}
}
}
删除某个元素
int LIST_deleteElement(LIST *head,void *Element,int ElementSize)
{
if(head==NULL)
return ptr_null; //ERROR_CODE类型,强制转换为整形输出了
LIST *temp=head,*aim=NULL;
while(temp)
{
if(memcmp(temp->next->pval,Element,ElementSize)) //如果不相等,下一个
{
temp = temp->next;
}
else
{
break; //如果找到了,直接返回,
}
}
if(memcmp(temp->next->pval,Element,ElementSize)) //如果是循环结束
{
return No_Element;
}
else //找到了元素
{
aim = temp->next;
temp->next = aim->next;
free(aim->pval);
free(aim);
return 0;
}
}
删除这个链表
void List_destroy(LIST* head)
{
if(head==NULL)
return ;
LIST *temp=head->next,*temp_next=temp->next; //头节点最后释放
void *pval;
while(temp_next)
{
free(temp->pval);
free(temp);
temp = temp_next;
temp_next = temp_next->next;
}
free(temp->pval); //释放最后一个节点
free(temp);
free(head); //释放头节点
}
测试代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"list.cpp"
#include"Sort.cpp"
#define ArrSize 9
#define POSTION 8
#define DELE_POS 1
int main(int argc,char **argv)
{
LIST *head;
LIST *temp;
int arr[ArrSize]={1,2,3};
InitArr(arr,ArrSize,ArrSize*30); //我自己另外实现的
PrintArr(arr,ArrSize); //我自己另外实现的
head = LIST_Init();
if(!LIST_add(head,arr,ArrSize,sizeof(int)))
{
temp=head->next;
while(temp->next)
{
printf("val is %d\n",*(int*)temp->pval);
temp=temp->next;
}
printf("val is %d\n",*(int*)temp->pval);
}
if(!LIST_GetElement(head,&arr[POSTION],sizeof(int),&temp))
printf("need get val is %d,get value is %d\n",arr[POSTION],*(int*)temp->pval);
LIST_deleteElement(head,&arr[DELE_POS],sizeof(int));
temp=head->next;
while(temp->next)
{
printf("val is %d\n",*(int*)temp->pval);
temp=temp->next;
}
printf("val is %d\n",*(int*)temp->pval); //打印最后一个元素
printf("链表删除以后\n");
List_destroy(head);
head=NULL; // free以后,head 一定要指向 null
return 0;
}
结果