Generic linked list? - c

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);
}

Related

Creating and Merging Linked Lists in C programming

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; };
};

How can I add numbers from a given array to a linked list without allowing duplicates?

I gotta write a function that takes the number from a given array and creates a linked list with them without allowing duplicates, my code works for adding the numbers but when I print the list I still get duplicate 4, it's like the function doesn't check if the number is already in the list and I can't find what's wrong.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node *next;
} SNode;
typedef SNode *TNode;
void makeList(int arr[], int len, TNode *head);
void printList(TNode head);
void main() {
TNode head = NULL;
int array[5] = { 1, 2, 4, 4, 8 };
makeList(array, 5, &head);
printList(head);
}
void makeList(int arr[], int len, TNode *head) {
TNode tmp1, tmp2 = *head;
int i, j;
for (i = 0; i < len; i++) {
if (tmp2 == NULL) {
tmp1 = (TNode)malloc(sizeof(SNode));
tmp1->data = arr[i];
tmp1->next = *head;
*head = tmp1;
}
while (tmp2 != NULL) {
if (tmp2->data != arr[i]) {
tmp1 = (TNode)malloc(sizeof(SNode));
tmp1->data = arr[i];
tmp1->next = *head;
*head = tmp1;
}
tmp2 = tmp2->next;
}
}
}
void printList(TNode head) {
TNode tmp = head;
while (tmp != NULL) {
printf("%d ", tmp->data);
tmp = tmp->next;
}
}
Never ever hide pointers behind the typedefs. It is a very bad practice.
I do not think that you need great performance, you can traverse the linked list
Use the correct type for sizes
Use object not types in sizeofs
Split the problem into smaller tasks (functions)
void main is wrong.
Do not cast the result of the malloc. If the code does not compile it means that you compile it using a C++ compiler wich is not correct.
Avoid double pointers and side effects if possible. Use function return values (instead of void func)
typedef struct Node {
int data;
struct Node* next;
} SNode;
SNode *makeList (const int arr[], size_t len, SNode *head);
void printList (SNode *head);
int main(void)
{
SNode *head, *tmp;
int array[5] = {1,2,4,4,8};
int array2[5] = {6,2,4,7,9};
head = makeList (array, 5, NULL);
if(head) printList (head);
printf("-------------------------\n");
tmp = makeList (array2, 5, head);
if(tmp)
{
head = tmp;
printList (head);
}
/* free the list */
}
int isInList(const int val, const SNode *head)
{
int result = 0;
while(head)
{
if(head -> data == val)
{
result = 1;
break;
}
head = head -> next;
}
return result;
}
SNode *add(int val, SNode *last)
{
if(!last) last = malloc(sizeof(*last));
else
{
last -> next = malloc(sizeof(*last));
last = last -> next;
}
if(last)
{
last -> data = val;
last -> next = NULL;
}
return last;
}
SNode *findLast(const SNode *head)
{
if(head)
{
while(head -> next) head = head -> next;
}
return (SNode *)head;
}
SNode *makeList (const int arr[], size_t len, SNode *head)
{
SNode *last = findLast(head);
while(len--)
{
if(!isInList(*arr, head))
{
last = add(*arr, last);
if(!head) head = last;
if(!last) break;
}
arr++;
}
return head;
}
void printList(SNode *head)
{
while(head) {printf("%d\n", head -> data);head = head -> next;}
}
https://godbolt.org/z/1Wssf6Gz9

C linked list to Display contents

Is there any part i have missed in the code?
I am creating a non-empty linked
list and to display the contents of a linked list. Where am I getting it wrong?
#include <stdbool.h>
#include <stdlib.h>
struct node_int
{
void *data;
node next;
};
typedef struct node_int *node;
typedef struct list_int { node first; } *list;
void init_list(list *lp, void *o)
{
*lp = (list) malloc(sizeof(struct list_int));
(*lp)->first = NULL;
(*lp)->first->data = o;
(*lp)->first->next = NULL;
}
void print(list ell, void (*print_data)(void *d))
{
list c;
c = ell;
while (c!NULL)
{
print_data(c->data);
c = ell;
}
}
There are a few problems with your code.
First like to say that I find it bad style to typedef a pointer. If you do that, you should at least use a name which clearly tells that the type is a pointer. Names like list and node make others think of something which is not pointers.
Below is some code showing how it could look without typedef'ed pointers.
#include <stdio.h>
#include <stdlib.h>
struct node_int
{
void *data;
struct node_int* next;
};
typedef struct node_int node;
typedef struct list_int { node* first; } list;
void init_list(list** lp, void *o)
{
// Allocate the list
*lp = malloc(sizeof(list));
if (*lp == NULL) return;
// Allocate the first node
(*lp)->first = malloc(sizeof(node));
if ((*lp)->first == NULL)
{
free(*lp);
*lp = NULL;
return;
}
// Initialize first element
(*lp)->first->data = o;
(*lp)->first->next = NULL;
}
void print(list* ell, void (*print_data)(void *d))
{
if (ell == NULL) return;
node* p = ell->first;
while (p != NULL)
{
print_data(p->data);
p = p->next;
}
}
void myPrint(void* d)
{
int* p = (int*)d;
printf("%d\n", *p);
}
void free_list(list* ell)
{
// Add code here ...
}
int main(void)
{
int a = 1;
list* myList;
init_list(&myList, &a);
if (myList == NULL) return 0;
// Use the list.....
print(myList, myPrint);
free_list(myList);
return 0;
}

gstack.c:14:3: error: unknown type name 'gqdata'

i am trying to implement a generic stack in C. I just wrote this raw piece of code and I am getting a big number of errors and warnings. However, one thing I do no understand is the following error (and other similar ones):
In file included from gstack.c:3:
./gstack.h:7:1: error: unknown type name 'gqueue'
gqueue create_queue();
^
./gstack.h:8:13: error: unknown type name 'gqueue'
int enqueue(gqueue *Q, gqdata *D);
^
./gstack.h:8:24: error: unknown type name 'gqdata'
int enqueue(gqueue *Q, gqdata *D);
gstack.h:
#ifndef _GSTACK_H_
#define _GSTACK_H_
void *gqueue;
void *gqdata;
gqueue create_queue();
int enqueue(gqueue *Q, gqdata *D);
int dequeue(gqueue *Q);
void to_string(gqueue *q);
#endif
gstack.c:
#include <stdio.h>
#include <stdlib.h>
#include "gstack.h"
void *gqueue;
void *gqdata;
typedef struct queue {
Node *tos;
} Queue;
typedef struct node {
Node *next;
gqdata data;
} Node;
gqueue create_queue(){
Queue queue = (Queue *)malloc(sizeof(Queue));
if (queue != NULL) {
queue->tos = NULL;
}
return queue;
}
int enqueue(gqueue *Q, gqdata *D) {
Queue queue = (Queue *) Q;
Node node = (Node *)malloc(sizeof(Node));
if (node != NULL) {
node->next = queue->tos;
node->data = D;
Q->tos = node;
return 1;
return 1;
} else {
return 0;
}
}
int dequeue(gqueue *Q) {
Queue *queue = (Queue *) Q;
if (queue == NULL || queue->tos == NULL) return 0;
queue->tos = queue->tos->next;
return 1;
}
void to_string(gqueue *Q) {
Queue *queue = (Queue *) Q;
if (queue == NULL || queue->tos == NULL) return 0;
queue->tos = queue->tos->next;
return 1;
}
void to_string(gqueue *Q) {
Queue *queue = (Queue *) Q;
Node *cursor = Queue->tos;
while(cursor != NULL) {
printf("%d\n");
cursor = cursor->next;
}
}
What am i doing wrong?
void *gqueue; void *gqdata; declares both gqueue and gqdata as variables that are pointers to void; thus, you can't use them as names of types. What exactly do you want gqueue and gqdata to be?
Move these lines from 'gstack.c' to 'gstack.h'
typedef struct queue {
Node *tos;
} Queue;
typedef struct node {
Node *next;
gqdata data;
} Node;
However, in 'gstack.h', change to this:
typedef struct node {
struct node *next;
gqdata data;
} Node;
typedef struct queue {
Node *tos;
} Queue;
Eliminate these lines from gstack.h:
void *gqueue;
void *gqdata;
Then, in both gstack.h and gstack.c replace all references to gqueue with 'Queue'
Then add the following line above the structure typedefs in gstack.h:
typedef void * gqdata;

C binary search tree with custom data

Suppose I got an external library bst that handles custom data types insertion in a bst
Here are the new_node,insert and search functions :
//new node
struct bst_node* new_node(void* data)
{
struct bst_node* result = malloc(sizeof(struct bst_node));
assert(result);
result->data = data;
result->left = result->right = NULL;
return result;
}
//insert node
void insert(struct bst_node** root, void* data) {
struct bst_node** node = search(root, data);
if (*node == NULL) {
*node = new_node(data);
}
}
//search node
struct bst_node** search(struct bst_node** root, void* data) {
struct bst_node** node = root;
while (*node != NULL) {
if (data, (*node)->data < 0)
node = &(*node)->left;
else if (compare_result > 0)
node = &(*node)->right;
else
break;
}
return node;
}
and the main.c ,suppose i read the models from a txt file :
#include <stdio.h>
#include <stdlib.h>
#include "bst.h"
#include <string.h>
#define MAX 50
typedef struct data_t{
int gg,mm,aaaa;
}data;
typedef struct accesories_t{
char name[MAX];
int price;
struct accesories_t *next;
}accesories;
typedef struct model_t{
//int index;
char name[MAX];
char file_a[MAX];
data date;
int price;
accesories *acs;
}model;
int main(int argc, char *argv[])
{
int menu=0;
char nf[MAX];
char name[MAX];
char fa[MAX];
int price,gg,mm,a;
strcpy(nf,argv[1]);
FILE *fp=fopen(nf,"+r");
model m;
struct bst_node* root = NULL;
while(fscanf(fp,"%s %d//%d//%d %d %s",name,gg,mm,a,price,fa)!=EOF){
strcpy(m.name,name);
strcpy(m.file_a,fa);
m.date.gg=gg;
m.date.mm=mm;
m.date.aaaa=a;
m.price=price;
m.index=index++;
insert(&root ,m);
}
system("PAUSE");
return 0;
}
So my question arises in the search function, how can i manage a comparator on custom data (let's say insert the models ordered by name (strcmp) ?
I'm very confused on how can i pass the names to the bst.c given that bst.c has no idea how my model struct is made.
Should I modify the bst library and maybe on bst struct add before data some sort of index and use that as comparator ?
OK I've managed to fix that by adding a string key inside the struct bst
What I'm trying to achieve now is to return the void* data type casted into struct model,
suppose _I got the tree with nodes containing the data, once I do a search I'd like to return for
example the data contained in a node and work on it, any clues ????
tried someting like without any success
suppose node is a returned node from a search function
model *m;
m=(model*)node->data;
how could I achieve this?
Example for using compare functions as callbacks. Definitions omitted for brevity.
int llist_cmp(struct llist *l, struct llist *r)
{
if (!l) return 1;
if (!r) return -1;
return strcmp(l->payload,r->payload);
}
struct llist * llist_split(struct llist **hnd, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *this, *save, **tail;
for (save=NULL, tail = &save; this = *hnd; ) {
if (! this->next) break;
if ( cmp( this, this->next) <= 0) { hnd = &this->next; continue; }
*tail = this->next;
this->next = this->next->next;
tail = &(*tail)->next;
*tail = NULL;
}
return save;
}
struct llist * llist_merge(struct llist *one, struct llist *two, int (*cmp)(struct llist *l, struct llist *r) )
{
struct llist *result, **tail;
for (result=NULL, tail = &result; one && two; tail = &(*tail)->next ) {
if (cmp(one,two) <=0) { *tail = one; one=one->next; }
else { *tail = two; two=two->next; }
}
*tail = one ? one: two;
return result;
}
BTW: the above snippet handles linked lists, but the mechanism for passing function pointers is the same as with trees, of course. And after all it was homework ;-)

Resources