通用链表? 我想知道是否有可能在C中使用链表的泛型函数,(我不想在C++中做,但是在C中)例子: struct first_struct { struct first_struct *next; int a; int b; }; struct second_struct { struct second_struct *next; int a; int b; int c; // just one more variable than first-struct };

通用链表? 我想知道是否有可能在C中使用链表的泛型函数,(我不想在C++中做,但是在C中)例子: struct first_struct { struct first_struct *next; int a; int b; }; struct second_struct { struct second_struct *next; int a; int b; int c; // just one more variable than first-struct };,c,linked-list,polymorphism,C,Linked List,Polymorphism,我是否强制每次为两个列表创建一个函数: add_node(struct first_struct *mystruct)// doesn't matter the function here juste let's assume they add correctly a node add_node1(struct second_struct *mystruct) //and so on each time i want to make some others function always mak

我是否强制每次为两个列表创建一个函数:

add_node(struct first_struct *mystruct)// doesn't matter the function here juste let's assume they add correctly a node
add_node1(struct second_struct *mystruct)
//and so on each time i want to make some others function always make them twice

或者有更好的方法吗?

更好的方法是抽象出链接处理(是什么使一个结构成为一个列表节点),然后用节点结构启动每个列表结构,重新使用它

像这样:

struct list_node {
  struct list_node *next;
};


struct first_struct {
  struct list_node list_node;
  int a;
  int b;
};


struct second_struct {
  struct list_node list_node;
  int a;
  int b;
  int c;
};
然后生成处理(指向)
struct list\u节点的指针的列表函数

这通常被称为“入侵列表”,因为它要求应用程序级数据结构“知道”可以将其放入列表中。这也意味着一个结构的实例一次只能在一个列表中


另一种方法是创建一个列表库,它只处理指向数据的指针(
void*
),这消除了限制,但带来了其他限制(更多的堆分配,当数据很小时会很烦人)。

我个人实现了一个通用链表:它通过提供一个函数来比较两个节点,还有一个可选的销毁节点的功能(释放字符串、关闭文件等)

#包括
#包括
类型定义结构链接{
作废*数据;
结构链接*上一个;
结构链接*下一步;
}联系美国;
类型定义结构列表{
链接头;
链尾;
尺寸链接;
/*函数指针*/
int(*数据比较)(常数无效*数据1,常数无效*数据2);
void(*Data_Destructor)(void*Data);
}名单;;
#定义列表构造函数(f_比较,f_析构函数){.head=NULL\
.tail=NULL\
.nbLink=0\
.Data\u Compare=f\u compar\
.Data_析构函数=f_析构函数}
void List_构造函数(List_*self,int(*数据比较)(const void*data1,const void*data2),void(*数据析构函数)(void*Data));
无效列表析构函数(列表自身);
bool列表添加(列表*自身,无效*数据);
void*List\u RemoveByLink(List\u*self,link\u*link);
作废*列表\删除数据(列表\自身,作废*数据);
无效*列表移除条件(列表自身,布尔(*数据条件)(常量无效*数据));
无效列表链接(列表自身、链接);
作废列表*数据(列表*自身,作废*数据);
无效列表条件(列表自身,布尔(*数据条件)(常量无效*数据));
无效列表排序(列表自身);
作废列表合并(列表到,列表从);
作废清单(清单本身);

这样,您就可以在列表中添加任何您想要的内容。只需小心使用propre comparison函数和destroy函数。

在结构中使用void指针可以非常轻松地实现通用链表

以下是我创建的此类列表的示例:

list.c

#include <stdlib.h>
#include "list.h"
#include <malloc.h>
#include <stdio.h>
#include <string.h>

void listNew(list* list, unsigned int elementSize, freeMemory freeFn,        
printList print) {

    list->numOfElem = 0;
    list->freeFn = freeFn;
    list->pr = print;
    list->head = NULL;
    list->sizeOfElem = elementSize;
}

node * listPushFront(list *list, void* data) {

    node *listNode = (node*)malloc(sizeof(node));

    if (listNode == NULL) {

        return NULL;
    }

    listNode->object = malloc(sizeof(list->sizeOfElem));

    if (listNode->object == NULL) {

        return NULL;
    }

    memcpy(listNode->object, data, list->sizeOfElem);

    listNode->pNext = list->head;
    list->head = listNode;

    list->numOfElem++;

    return listNode;
}

void listDestroy(list *list)
{
    node *current;

    while (list->head != NULL) {
        current = list->head;
        list->head = current->pNext;

        if (list->freeFn) {
            list->freeFn(current->object);
        }

        free(current->object);
        free(current);
    }
}

void listPrint(list *l) {

    node* temp = l->head;
    int i = 0;

    if (temp == NULL) {

        printf("\nEmpty list.");
        return;
    }

    while (temp) {

        printf("\nPrint element %d", i);

        l->pr(temp->object);
        temp = temp->pNext;

        i++;
    }
}
#include <stdlib.h>
#include "list.h"
#include <stdio.h>
#include <string.h>

typedef struct _TLV {

    unsigned int tag;
    unsigned int length;
    unsigned char* value;

}TLV;


void listFree(void* data) {

    TLV** ptr = (TLV**)data;

    free((*ptr)->value);
}

void Print(void* data) {

    TLV** ptr = (TLV**)data;

    printf("\nTag = %d", (*ptr)->tag);
    printf("\nLength = %d", (*ptr)->length);
    printf("\nValue = ");

    for (int i = 0; i < (*ptr)->length; i++) {

        printf("%d", (*ptr)->value[i]);
    }
}

TLV* allocateTLV(unsigned int tag, unsigned int length, unsigned char* 
value) {

    TLV* elem = (TLV*)malloc(sizeof(TLV));

    if (elem == NULL) {

        return NULL;
    }

    elem->tag = tag;
    elem->length = length;
    elem->value = (unsigned char*)malloc(length);

    if (value == NULL) {

        return NULL;
    }

    memcpy(elem->value, value, length);

    return elem;
}

int main()
{
    list l;
    TLV* tag;

    unsigned char test2[2] = { 1,2 };
    unsigned char test3[3] = { 1,2,3 };
    unsigned char test4[4] = { 1,2,3,4};

    listNew(&l, sizeof(TLV*), listFree, Print);

    tag = allocateTLV(2, sizeof(test2), test2);
    if (tag != NULL) {

        listPushFront(&l, &tag);
    }

    tag = allocateTLV(3, sizeof(test3), test3);
    if (tag != NULL) {

        listPushFront(&l, &tag);
    }

    tag = allocateTLV(4, sizeof(test4), test4);
    if (tag != NULL) {

        listPushFront(&l, &tag);
    }

    listPrint(&l);

    listDestroy(&l);

    return 0;
}
main.c

#include <stdlib.h>
#include "list.h"
#include <malloc.h>
#include <stdio.h>
#include <string.h>

void listNew(list* list, unsigned int elementSize, freeMemory freeFn,        
printList print) {

    list->numOfElem = 0;
    list->freeFn = freeFn;
    list->pr = print;
    list->head = NULL;
    list->sizeOfElem = elementSize;
}

node * listPushFront(list *list, void* data) {

    node *listNode = (node*)malloc(sizeof(node));

    if (listNode == NULL) {

        return NULL;
    }

    listNode->object = malloc(sizeof(list->sizeOfElem));

    if (listNode->object == NULL) {

        return NULL;
    }

    memcpy(listNode->object, data, list->sizeOfElem);

    listNode->pNext = list->head;
    list->head = listNode;

    list->numOfElem++;

    return listNode;
}

void listDestroy(list *list)
{
    node *current;

    while (list->head != NULL) {
        current = list->head;
        list->head = current->pNext;

        if (list->freeFn) {
            list->freeFn(current->object);
        }

        free(current->object);
        free(current);
    }
}

void listPrint(list *l) {

    node* temp = l->head;
    int i = 0;

    if (temp == NULL) {

        printf("\nEmpty list.");
        return;
    }

    while (temp) {

        printf("\nPrint element %d", i);

        l->pr(temp->object);
        temp = temp->pNext;

        i++;
    }
}
#include <stdlib.h>
#include "list.h"
#include <stdio.h>
#include <string.h>

typedef struct _TLV {

    unsigned int tag;
    unsigned int length;
    unsigned char* value;

}TLV;


void listFree(void* data) {

    TLV** ptr = (TLV**)data;

    free((*ptr)->value);
}

void Print(void* data) {

    TLV** ptr = (TLV**)data;

    printf("\nTag = %d", (*ptr)->tag);
    printf("\nLength = %d", (*ptr)->length);
    printf("\nValue = ");

    for (int i = 0; i < (*ptr)->length; i++) {

        printf("%d", (*ptr)->value[i]);
    }
}

TLV* allocateTLV(unsigned int tag, unsigned int length, unsigned char* 
value) {

    TLV* elem = (TLV*)malloc(sizeof(TLV));

    if (elem == NULL) {

        return NULL;
    }

    elem->tag = tag;
    elem->length = length;
    elem->value = (unsigned char*)malloc(length);

    if (value == NULL) {

        return NULL;
    }

    memcpy(elem->value, value, length);

    return elem;
}

int main()
{
    list l;
    TLV* tag;

    unsigned char test2[2] = { 1,2 };
    unsigned char test3[3] = { 1,2,3 };
    unsigned char test4[4] = { 1,2,3,4};

    listNew(&l, sizeof(TLV*), listFree, Print);

    tag = allocateTLV(2, sizeof(test2), test2);
    if (tag != NULL) {

        listPushFront(&l, &tag);
    }

    tag = allocateTLV(3, sizeof(test3), test3);
    if (tag != NULL) {

        listPushFront(&l, &tag);
    }

    tag = allocateTLV(4, sizeof(test4), test4);
    if (tag != NULL) {

        listPushFront(&l, &tag);
    }

    listPrint(&l);

    listDestroy(&l);

    return 0;
}
#包括
#包括“list.h”
#包括
#包括
类型定义结构{
无符号整数标记;
无符号整数长度;
无符号字符*值;
}TLV;
void listFree(void*数据){
TLV**ptr=(TLV**)数据;
自由((*ptr)->值);
}
作废打印(作废*数据){
TLV**ptr=(TLV**)数据;
printf(“\nTag=%d”,(*ptr)->标记);
printf(“\n长度=%d”,(*ptr)->长度);
printf(“\nValue=”);
对于(int i=0;i<(*ptr)->长度;i++){
printf(“%d”)(*ptr)->值[i];
}
}
TLV*allocateTLV(无符号整数标记、无符号整数长度、无符号字符*
价值){
TLV*elem=(TLV*)malloc(sizeof(TLV));
if(elem==NULL){
返回NULL;
}
元素->标签=标签;
元素->长度=长度;
元素->值=(无符号字符*)malloc(长度);
如果(值==NULL){
返回NULL;
}
memcpy(元素->值、值、长度);
返回元素;
}
int main()
{
清单l;
TLV*标签;
无符号字符test2[2]={1,2};
无符号字符test3[3]={1,2,3};
无符号字符test4[4]={1,2,3,4};
listNew(&l,sizeof(TLV*),listFree,Print);
tag=allocatelv(2,sizeof(test2),test2);
如果(标记!=NULL){
listPushFront(&l,&tag);
}
tag=allocatelv(3,sizeof(test3),test3);
如果(标记!=NULL){
listPushFront(&l,&tag);
}
tag=allocatelv(4,sizeof(test4),test4);
如果(标记!=NULL){
listPushFront(&l,&tag);
}
列表打印(&l);
列表销毁(&l);
返回0;
}

main.c是创建指向结构TLV的指针列表的一个示例。

您可以通过使用
c
的两个功能来实现通用链表,即
void
指针和函数指针

后者(函数指针)对于构建链表并不重要,但是如果您想对链表的数据做一些有用的事情,例如打印,则它是至关重要的

下面是一个完整的工作示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef struct node {
    void *data;
    struct node *next;
} node;


int lst_nodeAdd(
    node **head,
    node **tail,
    const void *data,
    size_t szData);

void lst_nodePrint(
    node *head,
    void(*print)(const void *));

void lst_nodeFree(node *head);

/* PRINTING FUNCTIONS */
void print_int(const void *a);
void print_string(const void *str);


int main(void)
{
    const char *str[] = {
        "0x0001",
        "0x0002",
        "0x0003",
    };

    // head & tail
    node *head = NULL; 
    node *tail = NULL;

    // List of strings
    lst_nodeAdd(&head, &tail, str[0], strlen(str[0]) + 1);
    lst_nodeAdd(&head, &tail, str[1], strlen(str[1]) + 1);
    lst_nodeAdd(&head, &tail, str[2], strlen(str[2]) + 1);

    lst_nodePrint(head, print_string);
    lst_nodeFree(head);
    head = NULL;
    tail = NULL;
    //....................................................

    // List of ints
    int int_array[] = {
        0,
        1,
        2,
    };
    lst_nodeAdd(&head, &tail, &int_array[0], sizeof(int));
    lst_nodeAdd(&head, &tail, &int_array[1], sizeof(int));
    lst_nodeAdd(&head, &tail, &int_array[2], sizeof(int));

    lst_nodePrint(head, print_int);
    lst_nodeFree(head);
    head = NULL;
    tail = NULL;


    system("PAUSE");
    return 0;
}


int lst_nodeAdd(
    node **head,
    node **tail,
    const void *data,
    size_t szData)
{
    void *tmp;
    tmp = malloc(sizeof(node));

    if (!tmp)
    {
        return 0;
    }

    ((node *)tmp)->next = NULL;
    ((node *)tmp)->data = malloc(szData);

    if (!((node *)tmp)->data)
    {
        free(tmp);
        return 0;
    }

    memcpy(((node *)tmp)->data, data, szData);

    if (!*head)
    {
        *head = (node *)tmp;
    }
    else
    {
        (*tail)->next = (node *)tmp;
    }
    *tail = (node *)tmp;
    return 1;
}

void lst_nodePrint(
    node *head,
    void(*print)(const void *))
{
    while (head)
    {
        print(head->data);
        head = head->next;
    }
}

void lst_nodeFree(node *head)
{
    node *tmp = head;
    while (head)
    {
        head = head->next;
        free(tmp->data);
        free(tmp);
        tmp = head;
    }
}

void print_int(const void *a)
{
    printf("%d\n", *(const int *)a);
}

void print_string(const void *str)
{
    puts((const char *)str);
}
#包括
#包括
#包括
类型定义结构节点{
作废*数据;
结构节点*下一步;
}节点;
int lst_nodead(
节点**头,
节点**尾部,
const void*数据,
大小(数据);
无效lst_节点打印(
节点*头,
无效(*打印)(常量无效*);
void lst_nodeFree(节点*头部);
/*打印功能*/
无效打印(const void*a);
无效打印字符串(const void*str);
内部主(空)
{
常量字符*str[]={
“0x0001”,
“0x0002”,
“0x0003”,
};
//头尾
node*head=NULL;
node*tail=NULL;
//字符串列表
第一个节点(&head,&tail,str[0],strlen(str[0])+1);
第一个节点(&head,&tail,str[1],strlen(str[1])+1);
第一个节点(&head,&tail,str[2],strlen(str[2])+1);
lst_nodePrint(打印头、打印字符串);
第一个诺德弗里(负责人);
head=NULL;
tail=NULL;
//....................................................
//INT列表
int_数组[]={
0,
1.
2.
};
lst_nodead(&head,&tail,&int_数组[0],sizeof(int));
第一个节点头(&head,&tail,&intar)