Home > database >  Generic LinkedLists in C
Generic LinkedLists in C

Time:05-16

I am quite new to C and having a lot of trouble with generic linked lists in c.

Im trying to convert my linked list into a generic one but I don't really understand how to.

This is my original one:

typedef struct LLNode {
    int rowPos;
    int colPos
    char Charecter
    struct LLNode *next;
} LLNode;

typedef struct LinkedList {
    LLNode *head;
    LLNode *tail;
    int ROW;
    int COL;
    int appleCount;
    int winCon;
    int snakeSize;                                   
} LinkedList;

I understand that the data has to be a void but can you have more than one void *data; in a node.

So far I have this:

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

typedef struct LinkedList {
    LLNode *head;
    LLNode *tail;
    int ROW;
    int COL;
    int appleCount;
    int winCon;
    int snakeSize;                                   
} LinkedList; 

But I don't know how I go about accessing and changing 3 lots of data in one void *data.

CodePudding user response:

You can use macros:

#define LNODE(Type) LNode_ ## Type
#define LLIST(Type) LList_ ## Type

#define DECL_LINKED_LIST(Type) \
    typedef struct LNODE(Type) { Type value; struct LNODE(Type)* next; } LNODE(Type); \
    typedef struct LLIST(Type) { LNODE(Type)* head; LNODE(Type)* tail; } LLIST(Type);

typedef struct {
    char const* f_name;
    char const* l_name;
} Person;

DECL_LINKED_LIST(Person);

int main() {
    LLIST(Person) list;
    LNODE(Person) node1;

    list.head = list.tail = &node1;
    node1.next = 0;
    node1.value.f_name = "John";
    node1.value.l_name = "Smith";
}

It's somewhat ugly, but it works. Alternatively, if you can use a C compiler instead, you can use templates.

CodePudding user response:

C does not have typed generic aggregates such as C templates, but you can implement simpler aggregates pointing to data items via void * pointers. You can also use macros to mix the data and the aggregation internals, but it requires more advanced C skills.

Here is an example using void * for data:

#include <stdio.h>
#include <stdlib.h>

/* generic list handling */
typedef struct LLNode {
    struct LLNode *next;
    void *data;
} LLNode;

typedef struct LinkedList {
    LLNode *head;
    LLNode *tail;
} LinkedList[1];

void LinkedList_init(LinkedList list) {
    if (list) {
        list->head = list->tail = NULL;
    }
}

void *LinkedList_append(LinkedList list, void *data) {
    if (list) {
        LLNode *node = malloc(sizeof(*node));
        if (node != NULL) {
            node->data = data;
            node->next = NULL;
            if (list->head == NULL) {
                list->head = list->tail = node;
            } else {
                list->tail = list->tail->next = node;
            }
            return data;
        }
    }
    return NULL;
}

void *LinkedList_delete(LinkedList list, void *data) {
    if (list) {
        for (LLNode **np = &list->head, *last = NULL; *np;) {
            LLNode *node = *np;
            if (node->data == data) {
                if ((*np = node->next) == NULL)
                    list->tail = last;
                free(node);
                return data;
            } else {
                last = node;
                np = &node->next;
            }
        }
    }
    return NULL;
}

void LinkedList_free(LinkedList list, int free_data) {
    if (list) {
        for (LLNode *node = list->head, *next; node; node = next) {
            next = node->next;
            if (free_data)
                free(node->data);
            free(node);
        }
        list->head = list->tail = NULL;
    }
}

#define LinkedList_foreach(var, list) \
        for (LLNode *np__ = (list)->head, *next__; np__ != NULL; np__ = next__) \
            for (var = (next__ = np__->next, np__)->data; np__; np__ = NULL)

/* use a generic list for my data */
typedef struct MyData {
    int rowPos;
    int colPos;
    char Character;
} MyData;

typedef struct MyList {
    int ROW;
    int COL;
    int appleCount;
    int winCon;
    int snakeSize;
    LinkedList list;  // linked list of MyData items
} MyList;

MyList *MyList_alloc(void) {
    MyList *lp = calloc(sizeof(*lp), 1);
    LinkedList_init(lp->list);
    return lp;
}

void MyList_free(MyList *lp) {
    LinkedList_free(lp->list, 1);
    free(lp);
}

MyData *MyList_add(MyList *lp, int row, int col, char c) {
    MyData *dp = malloc(sizeof(*dp));
    dp->rowPos = row;
    dp->colPos = col;
    dp->Character = c;
    return LinkedList_append(lp->list, dp);
}

void MyList_delete(MyList *lp, MyData *dp) {
    free(LinkedList_delete(lp->list, dp));
}

void MyList_print(MyList *lp) {
    printf("{\n");
    LinkedList_foreach(MyData *dp, lp->list) {
        printf("    { %d, %d, '%c' }\n", dp->rowPos, dp->colPos, dp->Character);
    }
    printf("};\n");
}

void MyList_filter_diagonal(MyList *lp) {
    LinkedList_foreach(MyData *dp, lp->list) {
        if (dp->rowPos == dp->colPos)
            MyList_delete(lp, dp);
    }
}

int main() {
    MyList *mylist = MyList_alloc();

    MyList_add(mylist, 0, 0, 'A');
    MyData *d1 = MyList_add(mylist, 1, 2, 'B');
    MyList_add(mylist, 2, 2, 'C');
    MyList_add(mylist, 3, 5, 'D');
    MyList_print(mylist);

    MyList_delete(mylist, d1);
    MyList_print(mylist);

    MyList_filter_diagonal(mylist);
    MyList_print(mylist);

    MyList_free(mylist);
    return 0;
}
  • Related