使链表更通用

时间:2016-06-02 03:23:24

标签: c list generics dynamic dynamic-arrays

有人可以帮我理解使用链表的void指针。

我有:

struct listNode
{
    int nodeValue;
    struct listNode * next;
};

typedef struct listNode listNode;

仅适用于整数。如果我将int nodeValue更改为void * nodeValue,我将如何使用void指针将值发送到链接列表中?

例如,我有一个添加到前面的功能:

void addFront(listNode *L, int number);

采用listNode和数字。

如果它是一个void *指针,我只需将签名更改为:

void addFront(listNode *L, void* value);

在使用整数的主函数中,我有类似的东西:

int main(void)
{   
    listNode *list;
    list = createList();

    for (int x = 0;x < 8;x++)
    {
        addFront(list,x);

    }

    return(0);
}

其中createList定义为:

listNode *createList()
{
    listNode *anyNode;
    anyNode = malloc(sizeof(listNode));
    anyNode->next = NULL;
    return anyNode;
}

listNode *initNode(int number)
{
    listNode *newNode;
    newNode = malloc(sizeof(listNode));
    newNode->nodeValue = number;
    newNode->next = NULL;
    return(newNode);
}

为了使列表更通用,我如何使用void *传递整数而不是声明整数。

3 个答案:

答案 0 :(得分:1)

不幸的是,这种通用行为的代价是开销很大:为了在列表上保存int,您需要通过动态分配int来扩展其范围:

listNode *initNode(int number)
{
    listNode *newNode;
    newNode = malloc(sizeof(listNode));
    newNode->nodeValue = malloc(sizeof(int));
    *(newNode->nodeValue) = number;
    newNode->next = NULL;
    return(newNode);
}

这会多次增加内存需求,因为malloc(sizeof(int));通常至少分配一个16字节的块。

答案 1 :(得分:0)

存储int或指针的一种方法是将nodeValue转换为union类型。请注意,为了避免未定义的行为,您的调用代码需要保持一致(即,如果您在链表中添加int,则不应尝试以后将它们作为指针访问,反之亦然)。

union intOrPointer
{
    int intValue;
    void * pointerValue;
};

struct listNode
{
    union intOrPointer nodeValue;
    struct listNode * next;
};

typedef struct listNode listNode;

listNode *initNode(int number)
{
    listNode *newNode;
    newNode = malloc(sizeof(listNode));
    newNode->nodeValue.intValue = number;
    newNode->next = NULL;
    return(newNode);
}

答案 2 :(得分:-1)

替代解决方案是将0-size数组用于listNode声明。 例如:

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

struct listNode
{
  struct listNode *next;
  int nodeValue[0];
};

struct listNode *addFront(struct listNode **head, void *data, size_t size)
{
  struct listNode *new_node = calloc(sizeof(struct listNode) + size, 1);
  if(!new_node)
    return NULL;
  new_node->next = *head;
  *head = new_node->next;
  memcpy(new_node->nodeValue, data, size);
}

void addInt2Front(struct listNode **head, int value)
{
  addFront(head, &value, sizeof(value));
}

int main(void)
{
  struct listNode *head = NULL;
  addInt2Front(&head, 5);
}

它减少了两次分配的开销,因为nodeValue的内存通过一次calloc()调用分配了listNode块。