I am making a set ADT for a school assignment, and I'm pretty close to completion. However I am having some difficulties as to how I should iterate over the various items in a struct:
It is essential that the "element" member of the set structure is a void pointer, if it was of the type int, I could set->element[i]. Any suggestions to alternatives?
struct set
{
void *element;
int size;
cmpfunc_t cmpfunc;
set_t *start;
set_t *next;
};
int set_contains(set_t *set, void *elem)
{
for(int i = 0;i<set->size;++i)
if(set->element[i] == elem)
return 1;
return 0;
}
Your ADT structure doesn't really make a lot of sense; it looks like you've tried to cross-breed different design patterns, those being the use of an array to hold the set elements, and the use of a linked-list to hold the set.
I'll take the liberty of modifying the structure so that it is a little more in line with either pattern. First of all, typedef's hide information -> avoid them whenever possible.
First pattern: Use an array of elements
struct set {
void **elements; /* array of elements */
int nElem; /* array count */
size_t elemSize; /* size of element type */
int(*cmpFunc)(void*, void*); /* equality comparison */
};
The elemSize field is used to allocate and copy new elements without knowing their datatype. This is common to both patterns, and to generic ADT's in general. To iterate over this set, use:
int set_contains(struct set *pSet, void *elem) {
for (int i = 0; i < pSet->nElem; ++i) {
if (pSet->cmpFunc(pSet->elements[i], elem))
return 1;
}
return 0;
}
Second pattern: Use a linked-list to represent the set
struct node {
void *data; /* element data */
struct node *next; /* next node in list */
};
struct set{
struct node *head; /* first element */
size_t elemSize; /* size of data type */
int(*cmpFunc)(void*, void*); /* equality comparison */
};
The element size and comparison function are attributes of a given set, not the data that is contained in that set, so they are defined on the set structure, not the node structure, which only defines the data and the associated link. To iterate over this set, use:
int set_contains(struct set *pSet, void *elem) {
struct node *head = pSet->head;
while(head) {
if (pSet->cmpFunc(head->data, elem))
return 1;
head = head->next;
}
return 0;
}
Related
#include <stdio.h>
#include <stdlib.h>
/**
* struct listint_s - Doubly linked list node
*
* #n: Integer stored in the node
* #prev: Pointer to the previous element of the list
* #next: Pointer to the next element of the list
*/
typedef struct listint_s // generating a structure
{
const int n;
struct listint_s *prev;
struct listint_s *next;
} listint_t;
/**
* create_listint - Creates a doubly linked list from an array of integers
*
* #array: Array to convert to a doubly linked list
* #size: Size of the array
*
* Return: Pointer to the first element of the created list. NULL on failure
*/
listint_t *create_listint(const int *array, size_t size)
{
listint_t *list;
listint_t *node;
int *tmp;
list = NULL;
while (size--)
{
node = malloc(sizeof(*node));
if (!node)
return (NULL);
tmp = (int *)&node->n;
*tmp = array[size];
node->next = list;
node->prev = NULL;
list = node;
if (list->next)
list->next->prev = list;
}
return (list);
}
I am having difficulty understanding these lines of code
while (size--)
and
tmp = (int *)&node->n;
When will the code exit the while loop, also i really want to understand how this piece of code works.
Within the structure
typedef struct listint_s // generating a structure
{
const int n;
struct listint_s *prev;
struct listint_s *next;
} listint_t;
the data member n is declared with the qualifier const. So you may not directly assign to it a value like for example
node->n = array[size];
The compiler will issue an error saying that you are trying to change a constant object.
So there is used a trick. At first there is declared a pointer to the object as a pointer to a non-constant object
int *tmp;
and this pointer is assigned with the address of the data member node->n using casting
tmp = (int *)&node->n;
The casting is required because the expression &node->n has the type const int *
And then using the pointer tmp a value is assigned to the constant object
*tmp = array[size];
As for this while loop
while (size--)
the it iterates while the number of elements in the array is not equal to 0. You may rewrite the while loop like
while ( size-- != 0 )
The function adds new elements in the beginning of the list storing in it values of the passed array starting from the last element of the array and down to the first element of the array. .
Pay attention to that the function is unsafe. It can produce memory leaks if some node will not be dynamically allocated due to this if statement
node = malloc(sizeof(*node));
if (!node)
return (NULL);
I'm working on a project that strictly requires to realize two set of functions in C with same signature that can be used from a sigle .c test file. one set is for a data structure, the other one for a different and incompatible data structure.
Since in C there is no polymorphism is not possible to call a function that has two implementation with same signature in two different headers (.h) files and taking for granted that the call will be referred to the right implementation of the function that is actually capable of managing the right data structure.
Ok I know it seems impossible and contradictory but..that is it...
I have to merge two generic items that can be list or dynamic array
Update:
on List.h (dynamicArray is in another .h)
typedef struct Node{
void *data;
struct Node *next, *prevNode;
} Node;
//typedef struct declaration List
typedef struct List {
struct Node *top, *bot, *prev;
int size;
} List;
//in the dynamicarray.h file:
typedef struct dynamicArray{
void **array;
size_t size;
size_t capacity;
}dynArray;
//in the dynamicarray.h file:
void* merge(void *element1,void *element2, int parameters){
void * returner;
if (parameters==ARRAY) {
returner= Array_Merge(element1,element2); // expected to receive two arrays
}
else {
returner= List_Merge(element1,element2); // expected to reveice two lists
}
return returner;
}
Do you have any suggestion to accomplish this request?
Thanks.
You need to pass both, a pointer to your function and some handler function to the test, along with argument(s). In 'c' void * can be use in place of any pointer. Something like the following might work for you:
int mytest(void*(*function)(void *), int(*handler)(void *), void *arg) {
if (handler(function(arg)))
return OK;
return FAIL;
}
So, you just need to have separate handler functions for arrays and lists and pass them to the test function along with other params.
Answering your last comment
I can imagine some scheme as the following.
List list1;
dyArray array1;
MergedList outList;
MergedArray outArray;
...
void *getNextArrayElement(dynArray *array){...}
void *getNextListElement(List *list){...}
int mergeAsList(void* el, void *list){
if (el == NULL)
return 0;
ListMember *mmb = malloc(sizeof(ListMember));
mmb->el = el;
mmb->next = ((MergeList*)list)->head;
(MergeList*)mergeList->head = mmb;
return 1;
}
int mergeAsArray(void *el, void *array) {
if (el == NULL)
return 0;
if (((MergeArray *)array)->index) >= MAX)
return 0;
((MergeArray *)array)[((MergeArray *)array)->index++] = el;
return 1;
}
int mergeAsSortedArray(void *el, void *array){...}
...
test(getNextArrayEelement, mergeAsList, &arraty1, &outList);
test(getNextListEelement, mergeAsList, &list1, &outArray);
...
int test (void *(get*)(void*),
int (merge*)(void *m1, void *result),
void *in,
void *out) {
void *el = get(in);
int res = merge(el, out);
return res;
}
Function pointers are the means in which you accomplish this.
Function pointers are what you would use if, for example, you wanted to pass a function to a sort function that told the sort function how to compare two adjacent members. Such a comparison function allows you to provide a generalized sort function that will work on a collection of any struct, since you can change out the comparison function to accommodate any struct.
Consider the following sort code:
typedef struct node{
void* item;
struct node* next;
} Node;
// Just an ordinary bubble sort
void sort(Node *start, bool greaterThan(void* a, void* b))
{
int swapped, i;
Node *ptr1;
Node *lptr = NULL;
/* Checking for empty list */
if (start == NULL)
return;
do
{
swapped = 0;
ptr1 = start;
while (ptr1->next != lptr)
{
if (greaterThan(ptr1->item, ptr1->next->item))
{
swap(ptr1, ptr1->next);
swapped = 1;
}
ptr1 = ptr1->next;
}
lptr = ptr1;
}
while (swapped);
}
// Swap function used above
void swap(Node *a, Node *b)
{
void* temp = a->item;
a->item = b->item;
b->item = temp;
}
To use it, we just need to define a payload to put into Node* item and a sort function to tell it how to order the items:
typedef struct {
int book_id;
char title[50];
char author[50];
char subject[100];
char ISBN[13];
} Book;
// Comparison function.
bool bookGreaterThan(void* left, void* right)
{
Book* a = (Book*)left;
Book* b = (Book*)right;
return strcmp(a->title, b->title) > 0;
}
Finally, you would sort your list like so:
// Pass a pointer to the first node in your list, and a function pointer to your comparer.
sort(pointerToMyList, bookGreaterThan);
A complete example can be found here.
See also Is it possible to achieve runtime polymorphism in C?
I am writing a generic function to create a linked list for structs.
Where I fall apart is in looping through the list to find where the
new node should go, as I'm unsure how to determine which struct type is
being used from within the function.
Am I able to use some if to determine the struct type?
Like
if(ID[0]==?? given that the IDs are common to both structs, but
the first char will determine struct type. I am thinking there must
be another way to determine the type using the type being passed to the function.
Sorry if this seems basic and I've overlooked something obvious.
Any thoughts would be appreciated.
typedef struct category* CategoryTypePtr;
typedef struct item* ItemTypePtr;
/*these structs have more members, but not relevant for this*/
typedef struct item
{
char itemID[ID_LEN + 1];
ItemTypePtr nextItem;
} ItemType;
typedef struct category
{
char categoryID[ID_LEN + 1];
CategoryTypePtr nextCategory;
ItemTypePtr headItem;
unsigned numItems;
} CategoryType;
typedef union types{
CategoryType cat;
ItemType item;
} Types;
int addNode(Types *type, char *str)
{
Types *new=NULL;
Types *current=NULL;
Types *prev = NULL;
Types *head=NULL;
char *ID;
const char* s ="|";
if((new=malloc(sizeof(Types)))== NULL)
{
fprintf(stderr,"Memory Allocation failure!!\n");
return false;
}
/*get ID from first str token this is uniform to both*/
ID=strtok(str,s);
current = head;
/* Search to find where in insert new list node*/
/*WHERE <XXXX> needs to be replace by cat or item, depending on which type it is*/
while (current != NULL && strcmp(current-><XXXX>->ID, ID)/*<<<---this is where I fall down
the XXXX represents cat or item*/
{
prev = current;
current = current->next;
}
/**
code to populate struct
a function that would be called
depending on Types type
*/
if (prev == NULL)
{
head = new;
}
else
{
prev->next = new;
}
return true;
}
Unlike some other languages, C doesn't have a built-in way to identify object types at runtime. Your method of putting an identifying character at the start of the structure is as good as any other.
HERE IS MY INSTRUCTIONS FOR THIS FUNCTION: Here an unsigned integer listsize is passed to this function you are to create a link list of size listsize. This will be performed by repeated use of malloc and calling setData to initialize the data into the struct plane fields. Each time you place the process in the list you need to place it so the list is sorted by the field distance (in ascending order). you return the head of the list
struct plane* list_intialize(unsigned int num)
{
struct plane *ptr,*head;
int i=0;
ptr = (struct plane*) malloc(num * sizeof(struct plane));
for (i = 0; i < num; ++i)
setData(ptr+i);
return ptr;
}
This started as a function skeleton inside an already completed program....I'm to complete the function so that it creates a link list. The setData is given function that inserts data to the structure elements.....MY problem is that after I run the current function it only returns one plane with information instead of num amount....am I using setData wrong or should my current setup work
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef _MY_DEF_
#define _MY_DEF_
enum dir {NE=0, EN, NW, WN, SE, ES, SW, WS};
enum loc {LNE=0, LNW,LSE,LSW};
struct plane{
short flightCode;
long xCord;
long yCord;
double distance;
char direction;
enum dir flightPattern;
enum loc location;
struct plane *nextPlane;
};
#endif
struct plane* sortByDist(struct plane*);
struct plane * radarPrint(struct plane*head);
int checkPlane(struct plane *);
int checkForCollision(struct plane*);
void setData(struct plane *pLane);
You need to allocate your list by allocating each node. One way of doing that while chaining the list forward is the code below:
struct plane* list_intialize(unsigned int num)
{
struct plane *head, **pp = &head;
int i=0;
for (i=0; i<num; ++i)
{
*pp = malloc(sizeof(**pp));
setData(*pp);
pp = &(*pp)->nextPlane;
}
*pp = NULL;
return head;
}
How It Works
This uses a pointer-to-pointer to always hold the address of the location where the nextPlane dynamo node address is stored. It starts with the address of the head pointer. With each new node, pp is filled the address of that node's nextPlane member. Once finished, it holds the address of the last node's nextPlane pointer, which it sets to NULL. The first node, pointed to by head, is returned. (and yes, this works even if you passed num = 0 for the requested size, in which case you would get back zero nodes: i.e. NULL).
Note: Don't forget, you need to free each node when releasing the list, extracting a single node out, etc. For example, to delete an entire list:
void list_delete(struct plane **lst)
{
while (*lst)
{
struct node *victim = *lst;
*lst = victim->nextPlane;
free(victim);
}
}
Invoked like this:
struct plane *lst = list_initialize(N);
// use list.., maybe adding nodes, removing them, changing, etc...
list_delete(&lst);
How to print your list:
void list_print(const struct plane *lst)
{
while (lst)
{
// TODO: print list node pointed to by lst.
// Ex: (x,y) coords
printf("(%d,%d) ",lst->xCord, lst->yCord);
lst = lst->nextPlane;
}
printf("\n");
}
You are not setting the links between the objects. In the for loop, you need:
ptr[i]->nextPlane = ptr[i+1];
At the end of the loop, make sure the last object points to NULL.
ptr[i-1] = NULL;
I am not too experienced in C and I am having trouble with something that might be simple you for most of you. Basically, I have this structure that defines a 'generic' queue with a resizing array implementation:
typedef void (*free_fptr)(void *);
typedef struct {
void **queue; // pointer to generic type
size_t first; // head index in array
size_t last; // tail index in array
size_t size; // number of elements
size_t capacity; // capacity of array
size_t elem_size; // size in bytes of each element in queue
free_fptr deleter; // function used to free each element
} Queue;
Now, I have a data type that I want to put in the queue :
typedef struct {
Process_state state;
Queue time_queue;
unsigned int start_time;
unsigned int id;
} Process;
I also have a function 'Queue_destroy(Queue *q)' that I want to call when I need to free each element in the queue :
void
Queue_destroy(Queue *q)
{
size_t i;
for (i = 0; i < q->size; ++i) {
q->deleter(q->queue[(q->first + i) % q->capacity]);
}
free(q->queue);
}
Now, my problem is that I don't know to access to the 'Process' queue inside the queue from a void pointer. For example :
void
Process_deleter(void *item)
{
// Here I want to access the queue inside (Process *)item
free((Process *)item);
}
I tried many things without success such as :
Queue_destroy((*(Process *)item).time_queue);
Queue_destroy((Process *)item->time_queue);
It does not compile and I am clueless!
Any help would be greatly appreciated!
Your function:
Queue_destroy(Queue *q)
expects a Queue*
So, change:
Queue_destroy((*(Process *)item).time_queue); // Here you are passing the object
to:
Queue_destroy(&(((Process *)item)->time_queue));
Assuming item is a pointer to your struct Process