Search code examples
cmemorylinked-listmallocvoid

Creating a new node with given value in a generic linked list in C with void pointers


I'm writing a library for generic linked lists in C using void pointers. This is my node:

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

and this is the function I use to create a new node with given data:

List* newNode (void* data) {
    List* newNode = (List*)malloc(sizeof(List));
    if (newNode) {
        newNode->data = malloc(sizeof(data));
        newNode->data = data;
        newNode->next = NULL;
    }
    return newNode;
}

I have no idea how to substitute the newNode->data = data line in order to make the assignment work. I tried using memcpy(newNode->data, data, sizeof(data)) but it seems like it only works with strings. Also, I'm not sure about evaluating sizeof(data) inside the function since I'm afraid it wouldn't return the correct value.

What would be the correct way of proceeding to copy the new data inside the data field of the new node?


Solution

  • You have to decide if you want your list to store pointers to values or if you want to store values themselves.

    If you want to store only pointers and let the user of your library care about memory allocation of elements, then:

    List* newNode (void* data) {
        List* newNode = malloc(sizeof(List));
        if (newNode) {
            newNode->data = data;
            newNode->next = NULL;
        }
        return newNode;
    }
    

    is fine. If you want to store values, you have to pass the size of the object to your function to know how much to allocate and copy:

    List* newNode(void* data, size_t datasize) {
        List* newNode = malloc(sizeof(List));
        if (newNode) {
            newNode->data = malloc(datasize);
            if (!newNode->data) {
                 free(newNode);
                 return NULL;
            }
            memcpy(newNode->data, data, datasize);
            newNode->next = NULL;
        }
        return newNode;
    }
    int main() {
        int a;
        List *l = newNode(&a, sizeof(a));
    }
    

    I'm not sure about evaluating sizeof(data) inside the function since I'm afraid it wouldn't return the correct value.

    data is a void*, so sizeof(data) gives you sizeof(void*) - size of a void* pointer.


    how can we do that since void* pointer can't be de-referenced?

    Create a function that prints one element and apply it on each list element. In pseudocode:

    void list_apply_foreach(list *t,
          void (*apply)(void *elem, void *cookie), void *cookie) {
       for (iterate over list in t) {
          apply(i->data, cookie);
       }
    }
    
    void print_int(void *elem, void *cookie) {
        printf("%d ", *(int*)elem);
    }
    
    int main() {
         list *l = list_make_list_of_ints(1, 2, 3, 4);
         list_apply_foreach(l, print_int);
    }