A generic list is likely to be singly-linked, and probably assumes that the items in the list have a structure like this:
typedef struct list_item list_item;
struct list_item
{
list_item *next;
...data for node...
};
Using this layout, you can write functions to manipulate lists using just the next pointers.
Sometimes, the '...data for node...
' will be a simple 'void *
'; that is, the list items will contain pointers to the next node in the list (or NULL if there is no next node) and pointers to the data.
typedef struct list list;
struct list
{
list *next;
void *data;
};
Since you can cast any pointer to 'void *
', you can have any mix of data types in the list - but your code must know how to handle them.
You ask about 'a' generic list function, but there probably isn't a single one-function-does-all design, and certainly not a simple one. There are a number of possible sets of functions that could make generic list functions. One set, inspired by Lisp, would consist of:
void *car(list *lp); // Return the data for the first item on the list
list *cdr(list *lp); // Return the tail of the list
list *cons(list *lp1, list *lp2); // Construct a list from lists lp1 and lp2
list *cond(list *lp, void *data); // Append data item to list
You probably want to provide the ability to test whether the list is empty, and a few other items.
One good exposition, admittedly in C++, is found in Koenig's "Ruminations on C++". The ideas can be adapted into C quite easily - it isn't dreadfully hard (though the storage management in C is harder than in C++).