Of course, we could make a generic list in a C++ style way:
This would be "list.h":
Code:
sstruct objops
{
int (*compare)(void *a, void *b);
void (*copy)(void *dest, void *src);
size_t (*size)(void *a);
};
struct node;
struct list
{
struct objops *ops;
struct node *head;
struct node *tail;
};
void ListInit(struct list *list, struct objops *ops);
void *ListFind(struct list *list, void *obj);
void ListAddAtEnd(struct list *list, void *obj);
void ListAddAtStart(struct list *list, void *obj);
void ListRemove(struct list *list, void *obj);
I'm not going to implement ALL of those functions, but here is a sample of what list.c would look like:
Code:
#include "list.h"
#include <stdlib.h>
struct node
{
struct node *next;
void *obj;
};
void ListInit(struct list *list, struct objops *ops)
{
list->head = NULL;
list->tail = NULL;
list->ops = ops;
}
static struct node*FindNode(struct list *list, void *obj)
{
struct node *p;
for(p = list->head; p; p = p->next)
{
if (list->ops->compare(p->obj, obj) == 0)
{
return p;
}
}
return NULL;
}
void *ListFind(struct list *list, void *obj)
{
struct node *node = FindNode(list, obj);
if (node)
return node->obj;
return NULL;
}
void ListAddAtEnd(struct list *list, void *obj)
{
struct node *node = malloc(sizeof(*node));
void *newobj = malloc(list->ops->size(obj));
if (newobj == NULL || node == NULL)
{
fprintf(stderr, "Fail to allocate memory\n");
exit(1);
}
list->ops->copy(newobj, obj);
node->obj = newobj;
node->next = NULL;
if (list->head == NULL)
{
list->head = list->tail = node;
}
else
{
list->tail->next = node;
list->tail = node;
}
}
To use it, we could consider something like this:
Code:
#include <stdio.h>
#include <string.h>
#include "list.h"
int intCompare(void *a, void *b)
{
int *pa = a;
int *pb = b;
if (*pa == *pb) return 0;
if (*pa > *pb) return 1;
return -1;
}
void intCopy(void *dest, void *src)
{
int *pdest = dest;
int *psrc = src;
*pdest = *psrc;
}
size_t intSize(void *obj)
{
return sizeof(int);
}
struct objops intOps =
{
intCompare,
intCopy,
intSize
};
// Because of the way the functions are defined, we need to wrap the string functions:
int mystrcmp(void *a, void *b)
{
return strcmp((char *)a, (char *)b);
}
void mystrcpy(void *dest, void *src)
{
strcpy((char *)dest, (char *)src);
}
size_t mystrlen(void *obj)
{
return strlen((char *)obj);
}
struct objops strOps =
{
mystrcmp,
mystrcpy,
mystrlen
};
int main()
{
struct list intList;
struct list strList;
int *p;
int x;
char *a;
char *b;
ListInit(&intList, &intOps);
x = 3;
ListAddAtEnd(&intList, &x);
x = 7;
ListAddAtEnd(&intList, &x);
x = 3;
p = ListFind(&intList, &x);
if (p)
printf("Found %d\n", *p);
else
printf("Could not find %d\n", x);
ListInit(&strList, &strOps);
ListAddAtEnd(&strList, "Hello");
ListAddAtEnd(&strList, "World");
a = ListFind(&strList, "Hello");
b = ListFind(&strList, "World");
printf("%s %s\n", a, b);
return 0;
}
I just typed that in, so it probably won't compile, but it should give you an idea of how to solve the problem.
Of course, C++ solves this much neater.
Edit: Updated the code after compiling it.
Edit2: The "ops" is essentially the vtable of the "class" in this case.
--
Mats