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
Related
I just learned about circular queues in class and I'm still confused, I know that without the empty cell we wouldn't be able to distinguish between an empty queue and a a queue with one element, but why ?
I used f.h for prototypes and f.c as implementation:
f.h:
#define n 50
struct queue
{
int key[n];
unsigned head;
unsigned tail;
};
void cree(struct queue *);
unsigned empty(struct queue);
int first(struct queue);
void enqueue(int, struct queue *);
void dequeue(struct queue *);
then f.c:
#include <assert.h>
#include "f.h"
void cree(struct queue *q)
{
q->head = 0;
q->tail = 0;
}
unsigned empty(struct queue q)
{
return (q.head == q.tail);
}
int first(struct queue q)
{
unsigned i;
assert(!empty(q));
i = q.head + 1;
if(i>n-1)
{
i = 0;
}
return(q.key[i]);
}
void enqueue(int x, struct queue *q)
{
q->tail++;
if(q->tail>n-1)
{
q->tail = 0;
}
assert(q->head != q->head);
q->key[q->tail] = x;
}
void dequeue(struct queue *q)
{
assert(!empty(*q));
q->head++;
if(q->head>n-1)
{
q->head =0 ;
}
}
You've got this a little bit wrong in 2 ways. The first way is that the confusion is between an empty queue and a full queue, not a queue with 1 element. Keeping one cell empty changes what it means to be "full".
So, given a circular queue, how do you determine how many elements it has in it?
You would like to write size = (end_position - start_position) % array_length. In fact, the % operator probably doesn't work like you want in your language, though, so you'll write size = (array_length + end_position - start_position) % array_length
If the queue is empty, you get size == 0, which is what you want. If the queue has array_length elements in it, though, you also get size == 0, which is wrong. You can fix that by ensuring that the number of elements is always less than the array length.
The other way you have this wrong is the "wouldn't be able to" part. It's almost always wrong to say that. If you store start_position and size, for example, instead of start_position and end_position, then it's easy to distinguish full from empty, and you can put array_length elements in your queue.
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 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;
}
I create a Queue that includes a two dimensional array, the size of every element of that array is 2. An Exception occurs when I enqueue a 2-size array in the queue.
The following is my code:
#include "stdio.h"
#define size 1000
typedef struct Queue {
int *data[2];
int front;
int rear;
}Queue;
void init(Queue *q)
{
q->front=0;
q->rear=0;
}
void Enqueue(Queue *q,int *value)
{
if(q->rear==size)
return ;
q->data[q->rear++]=value;
}
void main()
{
Queue q[1];
init(q);
int a[10][2];
for(int i=0;i<10;i++) {
a[i][0]=i;
a[i][1]=i*2+1;
Enqueue(q,a[i]);
}
}
*I create a Queue that includes a two dimensional array*
No you just create a pointer array in onw dimensional by int *data[2];
If you want create a Quene that include a two demensional array , it will be int data[size][size_anoter]
However, you didn't need I two dimensional . In void Enqueue(Queue *q,int *value) function , you pass the address from a[i] to data[i] . So you only need a big enough pointer array ;\
int * data[size];
Besides , It is better if you can define size as SIZE.
probably, Feel like the following
#include <stdio.h>
#include <stdlib.h>
#define size 1000
typedef struct Queue {
int (**data)[2];
int front;
int rear;
} Queue;
void init(Queue *q){
q->front=0;
q->rear=0;
q->data = malloc(size*sizeof(int (*)[2]));
}
void Enqueue(Queue *q,int (*value)[2]){
if(q->rear==size)
return ;
q->data[q->rear++]=value;
}
int main(){
Queue q[1];
init(q);
int a[10][2];
for(int i=0;i<10;i++) {
a[i][0]=i;
a[i][1]=i*2+1;
Enqueue(q, &a[i]);
}
//printf("%d\n", (*q->data[0])[1]);
return 0;
}
I can see at least a couple of issues:
typedef struct Queue {
int *data[2];
This is not a pointer to a two-dimensional array of ints, which I assume was what was intended. It is an array of two int pointers.
For a 2D array of 1000 entries of arrays with two elements, you probably wanted:
typedef struct Queue {
int data[size][2];
Then, when you call Enqueue(), copy in the array of two ints into the appropriate entry indicated by rear:
void Enqueue(Queue *q,int value[2])
{
if(q->rear==size)
return ;
memcpy(q->data[q->rear], value, sizeof(q->data[q->rear]));
q->rear++;
}
This solution will make a fixed array. If you want the array to be built dynamically it is a little more complicated as you need to malloc/calloc the memory and then free it when done.
I'm working with a binary search tree data structure to sort a series of structs with the type definitions:
typedef struct {
char c;
int index;
} data_t;
typedef struct node node_t;
typedef node {
void *data;
node_t *left;
node_t *right;
}
The node_t typedef is from a library provided to me for this purpose, presumably with a void* pointer to ensure polymorphism. node will be passed into the function:
static void
*recursive_search_tree(node_t *root,
void *key, int cmp(void*,void*))
Within the recursive_search_tree function, I want to be able to modify the code to use the index element as a condition to find the match closest to the index of the linear pass over an array of characters, which would ultimately involve a data_t being passed into *key and key->index being accessed within the function.
The Question
Is it possible to access key->index where key is a void* pointing to a data_t struct, or would this only be possible if data_t was declared as the type for key? I have tried to do the latter, however even casting the pointer to an int doesn't seem to pass the compiler.
Sure it's possible, you'd cast key as type *data_t. (As long as that's really what key points to!)
key /* argument of type void* */
(data_t*)key /* cast as type data_t* */
((data_t*)key)->index /* dereferenced */
Here is a simple example:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
char c;
int index;
} data_t;
typedef struct node {
void *data;
struct node *left;
struct node *right;
} node_t;
static int cmp(void *lhs, void *rhs)
{
return ((data_t *)lhs)->index - ((data_t *)rhs)->index;
}
int main(void)
{
data_t d0;
data_t d1;
d0.c = 'A';
d0.index = 1;
d1.c = 'B';
d1.index = 2;
printf("d0 < d1? %s\n", (cmp((void *)&d0, (void *)&d1) < 0 ? "yes" : "no"));
printf("d1 < d0? %s\n", (cmp((void *)&d1, (void *)&d0) < 0 ? "yes" : "no"));
return EXIT_SUCCESS;
}
This is type unsafe, as is any use of void. The use of void is generally because the intermediate is holding onto something it doesn't use for someone else's convenience.
This is a C function to let you hold whatever you want in a tree.
All it does is return whatever pointer you give it.
In your search function
int cmp(void* dt1, void* dt2)
{
data_t* data1 = (data_t*)dt1;
data_t* data2 = (data_t*)dt2;
/* Do what you need with data1 and data2 here */
}
Should let you do whatever you need. The problem you have is you need to cast your values inside the function. The parameters to cmp should exactly match the API for the library you are using, which says void* for the parameters.