Q:

Is it possible to write a generic traverse function in C for different list structures so long as they contain the "next" field?

First time asking a question but I did look around Google and stackoverflow to see if someone has asked something similar before. In malloc, recasting and free, it looked like the OP asked something similar for example. But it was more complicated.
I was wondering whether it's possible to create a generic function for a list structure in C that traverses the list given that you know that the different types of structures will always have a "next" field.
For example, given these two list-type structures:
typedef struct _list1 {
    int value;
    list1 *next;
} list1;

typedef struct _list2 {
    int value;
    char *string;
    list2 *next;
} list2;

Is it possible to create a generic void freeList((void *) list) function or something which looks something like the below? I am aware it's a simple thing to write both free functions for each individual list separately.
void freeList((void *) list) {
    // Included this because the structs would have different sizes
    // so I thought it would be possible to cast it in order to properly dereference the field.
    if (sizeof *list == sizeof list1)
        *list = (list1) list;
    else if (sizeof *list == sizeof list2)
        *list = (list2) list;

    if (!list) return;
    else {
        free(list->next);
        free(list);
    }
}

So far, my experiments with the code shown above didn't fare well given that gcc would complain about dereferencing a void * pointer.

A:

Making a heterogeneous list can be achieved by the use of a tagged union, or just a tag and casting:
struct list_item {
    struct list_item *next;
    enum datatype type;
    void *contents;
};

or
struct list_item {
    struct list_item *next;
    enum datatype type;
    union {
       int some_int;
       char some_char;
    } contents;
};

Then while traversing the list you just have to verify the type stored in type before using the contents of the element.

This check:
if (sizeof *list == sizeof list1)
    *list = (list1) list;
else if (sizeof *list == sizeof list2)
    *list = (list2) list;

doesn't work because sizeof is a static construct: its value is defined at compilation time. You're just asking for the sizeof void.

