Related
We are given the main function and structures, asked to create two different linked lists. One being in ascending order and another in descending order and then joined together without changing their order. To give an example,if we have L1: 1->3->4->6 and L2: 9->8->5->2, The final list would be 1->9->3->8->4->5->6->2. This below is my work. I'm having some problems.
This is the main function:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "function.h"
struct nodeFB *startFB = NULL;
struct nodeGS *startGS = NULL;
struct newNodeFB *startNewFB = NULL;
int main()
{
int id, age;
scanf("%d", &id);
while(id!=-1)
{
scanf("%d", &age);
insertFB(&startFB, id, age);
scanf("%d", &id);
}
scanf("%d", &id);
while(id!=-1)
{
insertGS(&startGS, id);
scanf("%d", &id);
}
printFB(startFB);
printGS(startGS);
createFinalList(&startNewFB,startFB,startGS);
printAll(startNewFB);
return 0;
}
These are the given structures and the functions I've written:
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
struct nodeFB
{
int id;
int age;
struct nodeFB *next;
};
struct nodeGS
{
int id;
struct nodeGS *next;
};
struct newNodeFB
{
int id;
int age;
struct newNodeGS *next;
};
struct newNodeGS
{
int id;
struct newNodeFB *next;
};
struct nodeFB *startFB;
struct nodeGS *startGS;
//functions
struct nodeFB *insertFB( struct nodeFB **startFB, int id, int age)
{//address of the first node in the linked list of FB
struct nodeFB *newnode, *ptr;
newnode = (struct nodeFB*)malloc(sizeof(struct nodeFB));
newnode->id = id;
newnode->age = age;
if (startFB == NULL) {
newnode->next = NULL;
*startFB = newnode;
}
else {
ptr = *startFB;
while(ptr->next!=NULL) {
ptr=ptr->next;
ptr->next= newnode;
newnode->next = NULL;
}
}
return *startFB;
}
void swap(struct nodeFB *a, struct nodeFB *b) {//function to swap two nodes
int temp = a->id;
a->id = b->id;
b->id = temp;
}
void sortFB(struct nodeFB *startFB) { //function to bubble sort the given linked list
int i;
int swapped;
struct nodeFB *ptr1;
struct nodeFB *ptr2= NULL;
if (startFB==NULL) { //checking for empty list
return; }
do {
swapped = 0;
ptr1=startFB;
while (ptr1->next !=ptr2) {
if (ptr1->id > ptr1->next->id) {
swap (ptr1, ptr1->next);
swapped = 1;
}
ptr1= ptr2->next;
}
ptr2=ptr1;
}
while (swapped);
}
void printFB(struct nodeFB *startFB) { //function to display the sorted list
struct nodeFB *ptr;
ptr = startFB;
sortFB(ptr);
while(ptr != NULL) {
printf("%d %d/n", ptr->id, ptr->age);
ptr=ptr->next;
}
}
struct nodeGS *insertGS(struct nodeGS **startGS, int id ) {
struct nodeGS *newnode, *ptr;
newnode = (struct nodeGS*)malloc(sizeof(struct nodeGS));
newnode->id = id;
if (startGS == NULL) {
newnode->next = NULL;
*startGS = newnode;
}
else {
ptr = *startGS;
while(ptr->next!=NULL) {
ptr=ptr->next;
ptr->next= newnode;
newnode->next = NULL;
}
}
return *startGS;
}
void swapGS(struct nodeGS *c, struct nodeGS *d) {//function to swap two nodes
int temp = c->id;
c->id = d->id;
d->id = temp;
}
void sortGS(struct nodeGS *startGS) { //function to bubble sort the given linked list
int i;
int swapped;
struct nodeGS *ptr1;
struct nodeGS *ptr2= NULL;
if (startGS==NULL) { //checking for empty list
return; }
do {
swapped = 0;
ptr1=startGS;
while (ptr1->next !=ptr2) {
if (ptr1->id < ptr1->next->id) {
swapGS (ptr1, ptr1->next);
swapped = 1;
}
ptr1= ptr2->next;
}
ptr2=ptr1;
}
while (swapped);
}
void printGS(struct nodeGS *startGS) {
struct nodeGS *ptr;
ptr = startGS;
sortGS(startGS);
while(ptr != NULL) {
printf("%d/n", ptr->id);
ptr = ptr->next;
}
}
**struct newNodeFB *createFinalList(struct newNodeFB **startNewFB, struct nodeFB *startFB, struct nodeGS *startGS ) {
struct newNodeFB *temp1, *ptr1;
temp1=(struct newNodeFB*) malloc(sizeof(struct newNodeFB));
temp1->id= startFB->id;
temp1->age=startFB->age;
struct newNodeGS *temp2;
temp2->id= startGS->id;
struct newNodeFB *temp3 = NULL;
struct newNodeGS *temp4 = NULL;
while (temp1 != NULL && temp2 != NULL)
{
ptr1=temp1;
while (ptr1->next!=NULL) {
ptr1=ptr1->next;
ptr1->next= temp2;
temp2->next=NULL;
}
temp3=temp1->next;
temp4= temp2->next;
temp1->next=temp2;
temp2->next=temp3;
temp1=temp3;
temp2=temp4;
}
startGS = temp2;
return startNewFB;
}**
void printALL(struct newNodeFB *startNewFB){
struct newNodeFB *ptr;
ptr= startNewFB;
while(ptr != NULL) {
printf("%d %d/n%d", startNewFB->id, startNewFB->age, startNewFB->id);
ptr=ptr->next;
}
}
The simplest way to create a merged list where the nodes alternate, is to simply iterate over both lists simultaneously and add each node from the two lists into a brand new list.
Because you want to alternate between the two lists, you need to use a single loop to iterate the lists, adding one node from the first list to the new merge-list, then adding one node from the second list. Stop when both lists are finished.
In pseudoish code it could look something like this:
Node *node1 = list1->head; // Node from first list
Node *node2 = list2->head; // Node from second list
// Loop while there are nodes in at least one of the lists
while (node1 != NULL || node2 != NULL)
{
if (node1 != NULL)
{
list_add_tail(merge_list, node1->data);
node1 = node1->next;
}
if (node2 != NULL)
{
list_add_tail(merge_list, node2->data);
node2 = node2->next;
}
}
As seen it's basically the same as iterating over a single list, copying data to a new list.
Another consideration is if one is mixing struct nodeFB and struct nodeGS in one list, how could the programme tell if the node is an FB or GS? Unless the lists are of equal sizes, where they are alternating, one loses type information by mixing them together.
There are several ways to get around this. One could only allow one type of node in one list; one has to convert the types to mix the lists. One might as well convert on input and have one type of list. A more nuanced approach is to store a pointer telling what type it is with every node.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
/* Circular definitions mean one has to forward declare. */
struct node;
static void foo_print(const struct node *);
static void bar_print(const struct node *);
/* Virtual table stores the type of node. */
typedef void (*print_fn)(const struct node *);
static const struct vt { print_fn print; }
foo_vt = { &foo_print }, bar_vt = { &bar_print };
/* A list of nodes. */
struct node { struct node *next; const struct vt *vt; };
struct list { struct node *head; };
/* Subclasses of node. */
struct foo_node {
struct node base;
int id, age;
};
struct bar_node {
struct node base;
int id;
};
/* Implementations of the above. */
static void foo_print(const struct node *node) {
const struct foo_node *ptr = (const struct foo_node *)node;
printf("(foo)%d age %d", ptr->id, ptr->age);
}
static void bar_print(const struct node *node) {
const struct bar_node *ptr = (const struct bar_node *)node;
printf("(bar)%d", ptr->id);
}
static struct node *foo_input(void) {
int id, age;
struct foo_node *foo;
if((printf("Id: "), scanf(" %d", &id) != 1) || id == -1
|| (printf("Age: "), scanf(" %d", &age) != 1)
|| !(foo = malloc(sizeof *foo))) return 0;
foo->base.vt = &foo_vt;
foo->id = id;
foo->age = age;
fprintf(stderr, "User entered %d, %d.\n", foo->id, foo->age);
return &foo->base;
}
static struct node *bar_input(void) {
int id;
struct bar_node *bar;
if((printf("Id: "), scanf(" %d", &id) != 1) || id == -1
|| !(bar = malloc(sizeof *bar))) return 0;
bar->base.vt = &bar_vt;
bar->id = id;
fprintf(stderr, "User entered %d.\n", bar->id);
return &bar->base;
}
//address of the first node in the linked list
static void push(struct list *start, struct node *node) {
assert(start && node);
node->next = start->head, start->head = node;
}
static void printAll(const struct list *list) {
struct node *node;
for(node = list->head; node; node = node->next)
printf("%s", node == list->head ? "" : ", "), node->vt->print(node);
printf(".\n");
}
/** Interleaves the list `bars` with the list `foos`. `bars` will be the empty
list and `foos` will have all of the elements. */
static void createFinalList(struct list *foos, struct list *bars) {
/* Create this function. */
(void)foos, (void)bars;
}
int main(void) {
struct list foos = { 0 }, bars = { 0 };
struct node *node;
while(node = foo_input()) push(&foos, node);
while(node = bar_input()) push(&bars, node);
printf("foos: "), printAll(&foos);
printf("bars: "), printAll(&bars);
createFinalList(&foos, &bars);
printf("now,\n");
printf("foos: "), printAll(&foos);
printf("bars: "), printAll(&bars);
/* fixme: Memory leak, clean up. */
return 0;
}
If one really cannot modify the nodes, maybe encompass them in a union?
struct node {
const struct vt *vt;
union { struct nodeFB fb; struct nodeGS gs; };
};
struct item {
char name[32];
struct item *next;
};
struct item *create_item(char *name) {
struct item *result = malloc(sizeof(struct item));
strcpy(result->name, name);
result->next = NULL;
return result;
}
int equals(char *a, char *b) {
return strcmp(a, b) == 0;
}
void append(struct item **list, struct item *i){
i = malloc(sizeof(struct item));
struct item *last = *list;
strcpy(i->name, i->name);
i->next = NULL;
if(*list == NULL){
*list = i;
}
while(last->next != NULL) {
last = last->next;
}
last->next = i;
}
int main(void) {
struct item *list = NULL;
append(&list, create_item("Dog"));
append(&list, create_item("Cat"));
append(&list, create_item("Bat"));
assert(equals(list->next->next->name, "Bat"));
}
I would like to append a new struct node at the end of a list, but I get an error (segmentation fault) when I try to run main.
Can someone please help me? :-)
I think the problem might be that I am initializing the list with NULL in main, but I don't know what I need to change so the append-function can handle it.
You have several errors:
demo.c: In function ‘append’:
demo.c:26:13: warning: passing argument 1 to ‘restrict’-qualified parameter aliases with argument 2 [-Wrestrict]
26 | strcpy(i->name, i->name);
You malloc an already malloced object here:
i = malloc(sizeof(struct item)); // choose a better name, 'i' sucks :)
And the main problem, you never connect the head (list) in the append function.
Your code working:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
struct item {
char name[32];
struct item *next;
};
struct item *create_item(const char *name) // const added
{
struct item *result = malloc(sizeof(struct item));
strcpy(result->name, name);
result->next = NULL;
return result;
}
int equals(char *a, char *b)
{
return strcmp(a, b) == 0;
}
void append(struct item **list, struct item *item)
{
if (*list == NULL)
{
*list = item;
return;
}
struct item *next = *list;
struct item *tail = NULL;
while (next != NULL)
{
tail = next;
next = next->next;
}
tail->next = item;
}
int main(void)
{
struct item *list = NULL;
append(&list, create_item("Dog"));
append(&list, create_item("Cat"));
append(&list, create_item("Bat"));
assert(equals(list->next->next->name, "Bat"));
}
Please, next time provide a compilable snippet.
I want to print reversely the elements of a list using recursion, but I get an execution error !
Can someone help?
typedef struct node
{
int val;
struct node* next;
}node;
typedef struct list
{
node* head;
}list;
void display(list L)
{
if(L.head == NULL) return;
L.head= L.head->next;
display(L);
printf("%d\t",L.head->val);
}
void display(node *N){
if(N != NULL){
display(N->next);
printf("%d\t",N->val);
}
}
and in main:
int main (void)
{
//...
display (L.head);
Instead of using :
typedef struct list
{
node* head;
}list;
you can simply pass the "node n" instead, and call it recursively using n->next, as follows:
void display(node *n){
if(n != NULL){
display(n->next);
printf("%d\t",n->val);
}
}
And then call that method from the outside as follows:
display(node->head);
or
display(node.head);
Depending on how you have allocated the structure "node".
Side Note:
I would actually renamed your structures to:
typedef struct List
{
int val;
struct List* next;
}List;
and then call:
void display(List *l){
if(l != NULL){
display(l->next);
printf("%d\t",l->val);
}
}
IMO it better expresses the use-case in hand.
A Full example:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct List
{
int val;
struct List* next;
}List;
void display(List *l){
if(l != NULL){
display(l->next);
printf("%d\t",l->val);
}
}
List *addElement(List *l, int val){
if(l == NULL){
List *node = malloc(sizeof(List));
node->val = val;
node->next = NULL;
return node;
}
else
l->next = addElement(l->next, val);
return l;
}
void freeList(List *l){
if(l != NULL){
freeList(l->next);
free(l);
}
}
int main(){
List *l = NULL;
l = addElement(l, 1);
l = addElement(l, 2);
l = addElement(l, 3);
l = addElement(l, 4);
l = addElement(l, 5);
display(l);
freeList(l);
}
OUTPUT:
5 4 3 2 1
I have created a new struct that represents a linked list and two functions listDestroy and arr2list. The second function gets a generic array and converts it into a list. The code:
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(List* list, void freeElement(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
if (length == 0 || !copyElement || !freeElement) {
return NULL;
}
struct List* head = (struct List*) malloc(sizeof(struct List));
if (head == NULL) {
return NULL;
}
List* current_node = head;
for(int i = 0; i < length; i++) {
current_node->value = copyElement(array[i]);
struct List* new_node = (struct List*) malloc(sizeof(struct List));
if (new_node == NULL) {
listDestroy(head, freeElement);
return NULL;
}
current_node->next = new_node;
current_node = new_node;
}
return head;
}
I think that I have a problem with the copyElement(array[i]);. I want to pass a generic array of elements to arr2list but I'm not sure if void* array[] is the right way. If I change it to be void* array I get an error for array[i]. What is the right way to make it work? Is it possible to also show a working example?
The last node of the list ends up with a NULL next and a garbled value. I don't think this is what you wanted. Try this loop:
struct List* head = NULL;
struct List** tail = &head;
for(int i = 0; i < length; i++) {
*tail = malloc(sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = copyElement(array[i]);
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
This uses a pointer to pointer so that we can update head or next depending on where we are in the loop without an extra if condition. Note that the allocaction of head is inside the loop now, so we always allocate exactly as many nodes as we need.
void* array[] is completely valid in this scenario, although I don't see the point of copyElement.
Perhaps just remove it and use array[i] instead?
I'd also like to point out a few mistakes that you may want to fix in your code:
Don't cast the result of malloc and use sizeof(*var) instead of sizeof(type). They're unneeded and may cause issues later on if you change the type of head. So, change this (and any later occurrences):
struct List* head = (struct List*) malloc(sizeof(struct List));
to this:
struct List* head = malloc(sizeof(*head));
Consider returning struct List * from arr2list. Change this:
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
to this:
struct List* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
Also, use either struct List * or List *. Inconsistencies may make it hard to understand your code.
It may be clearer if you pass function pointers to your functions instead of just functions. So, instead of doing this:
returntype func(params),
do this:
returntype (*func)(params),
You may also want to change malloc calls to calloc calls. calloc zeroes out memory, which can help in debugging. Change:
malloc(...)
to:
calloc(1, ...)
Here's an example combining code fixes from Joshua's post and mine:
list.c:
#include <stdlib.h>
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(struct List* list, void (*freeElement)(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
struct List* arr2list(void* array[], int length, void (*freeElement)(void*)) {
struct List* head = NULL;
struct List** tail = &head;
if (length == 0 || !freeElement) {
return NULL;
}
for(int i = 0; i < length; i++) {
*tail = calloc(1, sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = array[i];
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
}
test.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.c"
void free_element(void *el)
{
free(el);
}
int main(void)
{
List *list;
int ctr;
void *array[4];
for(ctr = 0; ctr < 4; ctr++)
{
/* Don't usually pass sizeof(type) to malloc(),
* but these are extenuating circumstances. */
array[ctr] = malloc(sizeof(int));
if(!array[ctr]) return 1;
*(int *)array[ctr] = ctr * 4;
}
list = arr2list(array, sizeof(array)/sizeof(array[0]), free_element);
while(list)
{
printf("%d\n", *(int *)list->value);
list = list->next;
}
listDestroy(list, free_element);
return 0;
}
Output:
0
4
8
12
One last note: you may consider creating a header file that defines these structures and functions (and remove the structure from list.c). Here's an example:
#ifndef LIST_H
#define LIST_H 1
typedef struct List { // Remove this from list.c
struct List* next;
void *value;
} List;
void listDestroy(struct List*, void (*)(void*));
struct List* arr2list(void* [], int, void (*)(void*));
#endif
I was wondering if that was possible to use generic function for linked lists in C, (i don't want to do that in C++ but in C) example :
struct first_struct
{
struct first_struct *next;
int a;
int b;
};
struct second_struct
{
struct second_struct *next;
int a;
int b;
int c; // just one more variable than first-struct
};
am i force to make a function each time for the two lists :
add_node(struct first_struct *mystruct)// doesn't matter the function here juste let's assume they add correctly a node
add_node1(struct second_struct *mystruct)
//and so on each time i want to make some others function always make them twice
or is there a better way to do that ?
The better way is to abstract out the link handling (what makes a structure into a list node) and then re-use that by starting each listable structure with the node structure.
Like so:
struct list_node {
struct list_node *next;
};
struct first_struct {
struct list_node list_node;
int a;
int b;
};
struct second_struct {
struct list_node list_node;
int a;
int b;
int c;
};
Then make list functions that deal with (pointers to) struct list_node.
This is commonly called "intrusive lists", since it requires the application-level data structure to "know" that it's possible to put it in a list. It also means an instance of a structure can only be on one list at a time.
The other way is to make a list library that only deals with pointers to data (void *), that removes the limitation but brings others instead (more heap allocation, annoying when data is small).
Personally, I have implemented a generic linked list : it work by providing a function to compare two node, and an optional function to destroy a node (free string, close file, etc etc).
#include <stdbool.h>
#include <stddef.h>
typedef struct link {
void *data;
struct link *previous;
struct link *next;
} link_s;
typedef struct list {
link_s *head;
link_s *tail;
size_t nbLink;
/* function pointer */
int (*Data_Compare)(const void *data1, const void *data2);
void (*Data_Destructor)(void *data);
} list_s;
#define LIST_CONSTRUCTOR(f_compar, f_destructor) {.head = NULL, \
.tail = NULL, \
.nbLink = 0, \
.Data_Compare = f_compar, \
.Data_Destructor = f_destructor}
void List_Constructor(list_s *self, int (*Data_Compare)(const void *data1, const void *data2), void (*Data_Destructor)(void *data));
void List_Destructor(list_s *self);
bool List_Add(list_s *self, void *data);
void *List_RemoveByLink(list_s *self, link_s *link);
void *List_RemoveByData(list_s *self, void *data);
void *List_RemoveByCondition(list_s *self, bool (*Data_Condition)(const void *data));
void List_DestroyByLink(list_s *self, link_s *link);
void List_DestroyByData(list_s *self, void *data);
void List_DestroyByCondition(list_s *self, bool (*Data_Condition)(const void *data));
void List_Sort(list_s *self);
void List_Merge(list_s *to, list_s *from);
void List_Reverse(list_s *self);
This way, you can add whatever you want into the list. Just be carefull to have a propre comparison function and destroy function.
You can implement a generic linked list fairly easy using a void pointer in your struct.
Here is an example of a such list created by me:
list.c
#include <stdlib.h>
#include "list.h"
#include <malloc.h>
#include <stdio.h>
#include <string.h>
void listNew(list* list, unsigned int elementSize, freeMemory freeFn,
printList print) {
list->numOfElem = 0;
list->freeFn = freeFn;
list->pr = print;
list->head = NULL;
list->sizeOfElem = elementSize;
}
node * listPushFront(list *list, void* data) {
node *listNode = (node*)malloc(sizeof(node));
if (listNode == NULL) {
return NULL;
}
listNode->object = malloc(sizeof(list->sizeOfElem));
if (listNode->object == NULL) {
return NULL;
}
memcpy(listNode->object, data, list->sizeOfElem);
listNode->pNext = list->head;
list->head = listNode;
list->numOfElem++;
return listNode;
}
void listDestroy(list *list)
{
node *current;
while (list->head != NULL) {
current = list->head;
list->head = current->pNext;
if (list->freeFn) {
list->freeFn(current->object);
}
free(current->object);
free(current);
}
}
void listPrint(list *l) {
node* temp = l->head;
int i = 0;
if (temp == NULL) {
printf("\nEmpty list.");
return;
}
while (temp) {
printf("\nPrint element %d", i);
l->pr(temp->object);
temp = temp->pNext;
i++;
}
}
list.h
#ifndef __LIST_H
#define __LIST_H
typedef void(*freeMemory)(void*);
typedef void(*printList)(void*);
typedef struct _node {
void* object;
struct _node* pNext;
}node;
typedef struct _list {
unsigned int sizeOfElem;
unsigned int numOfElem;
node* head;
freeMemory freeFn;
printList pr;
}list;
void listNew(list* list, unsigned int elementSize, freeMemory freeFn,
printList print);
node * listPushFront(list *list, void* data);
void listDestroy(list *list);
void listPrint(list *l);
#endif
main.c
#include <stdlib.h>
#include "list.h"
#include <stdio.h>
#include <string.h>
typedef struct _TLV {
unsigned int tag;
unsigned int length;
unsigned char* value;
}TLV;
void listFree(void* data) {
TLV** ptr = (TLV**)data;
free((*ptr)->value);
}
void Print(void* data) {
TLV** ptr = (TLV**)data;
printf("\nTag = %d", (*ptr)->tag);
printf("\nLength = %d", (*ptr)->length);
printf("\nValue = ");
for (int i = 0; i < (*ptr)->length; i++) {
printf("%d", (*ptr)->value[i]);
}
}
TLV* allocateTLV(unsigned int tag, unsigned int length, unsigned char*
value) {
TLV* elem = (TLV*)malloc(sizeof(TLV));
if (elem == NULL) {
return NULL;
}
elem->tag = tag;
elem->length = length;
elem->value = (unsigned char*)malloc(length);
if (value == NULL) {
return NULL;
}
memcpy(elem->value, value, length);
return elem;
}
int main()
{
list l;
TLV* tag;
unsigned char test2[2] = { 1,2 };
unsigned char test3[3] = { 1,2,3 };
unsigned char test4[4] = { 1,2,3,4};
listNew(&l, sizeof(TLV*), listFree, Print);
tag = allocateTLV(2, sizeof(test2), test2);
if (tag != NULL) {
listPushFront(&l, &tag);
}
tag = allocateTLV(3, sizeof(test3), test3);
if (tag != NULL) {
listPushFront(&l, &tag);
}
tag = allocateTLV(4, sizeof(test4), test4);
if (tag != NULL) {
listPushFront(&l, &tag);
}
listPrint(&l);
listDestroy(&l);
return 0;
}
main.c is an example of creating a list of pointers to the struct TLV.
You could implement a generic linked list by using two features of C, namely void pointers and function pointers.
The latter (function pointers) is not crucial for building the linked list, but it is crucial if you want to do something useful with the data of the linked list such as printing.
Here is a full working example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
void *data;
struct node *next;
} node;
int lst_nodeAdd(
node **head,
node **tail,
const void *data,
size_t szData);
void lst_nodePrint(
node *head,
void(*print)(const void *));
void lst_nodeFree(node *head);
/* PRINTING FUNCTIONS */
void print_int(const void *a);
void print_string(const void *str);
int main(void)
{
const char *str[] = {
"0x0001",
"0x0002",
"0x0003",
};
// head & tail
node *head = NULL;
node *tail = NULL;
// List of strings
lst_nodeAdd(&head, &tail, str[0], strlen(str[0]) + 1);
lst_nodeAdd(&head, &tail, str[1], strlen(str[1]) + 1);
lst_nodeAdd(&head, &tail, str[2], strlen(str[2]) + 1);
lst_nodePrint(head, print_string);
lst_nodeFree(head);
head = NULL;
tail = NULL;
//....................................................
// List of ints
int int_array[] = {
0,
1,
2,
};
lst_nodeAdd(&head, &tail, &int_array[0], sizeof(int));
lst_nodeAdd(&head, &tail, &int_array[1], sizeof(int));
lst_nodeAdd(&head, &tail, &int_array[2], sizeof(int));
lst_nodePrint(head, print_int);
lst_nodeFree(head);
head = NULL;
tail = NULL;
system("PAUSE");
return 0;
}
int lst_nodeAdd(
node **head,
node **tail,
const void *data,
size_t szData)
{
void *tmp;
tmp = malloc(sizeof(node));
if (!tmp)
{
return 0;
}
((node *)tmp)->next = NULL;
((node *)tmp)->data = malloc(szData);
if (!((node *)tmp)->data)
{
free(tmp);
return 0;
}
memcpy(((node *)tmp)->data, data, szData);
if (!*head)
{
*head = (node *)tmp;
}
else
{
(*tail)->next = (node *)tmp;
}
*tail = (node *)tmp;
return 1;
}
void lst_nodePrint(
node *head,
void(*print)(const void *))
{
while (head)
{
print(head->data);
head = head->next;
}
}
void lst_nodeFree(node *head)
{
node *tmp = head;
while (head)
{
head = head->next;
free(tmp->data);
free(tmp);
tmp = head;
}
}
void print_int(const void *a)
{
printf("%d\n", *(const int *)a);
}
void print_string(const void *str)
{
puts((const char *)str);
}