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.
Related
I am trying to construct a bus network using adjacent linked list graph data structure.
A simplified code is shown below:
typedef struct BusNetwork
{
struct AdjStopList *stopsArray; //defing the array of pointers
} BusNetwork;
typedef struct Node
{
int stopID;
struct Node *next;
} Node;
typedef struct AdjStopList
{
char stopName[20];
int numOfAdjStp;
struct Node *first;
} AdjStopList;
void insertStopAtLast(AdjStopList *L, int stopID)
{
//add stopID to the last node of the list
return;
}
void addBusRoute(AdjStopList *L[], int from, int to)
{
if (from == to)
return;
insertStopAtLast(L[from], to);
return;
}
void main(BusNetwork *BN, int from, int to)
{
addBusRoute(BN->stopsArray, from, to);
}
The problem is with addBusRoute(BN->stopsArray, from, to); It seems I didn't pass the same type of value as function argument. But my understanding of BN->stopsArray is an array of pointers, which should be the same as AdjStopList L[]. What went wrong?
The argument AdjStopList *L[] has the same meaning as AdjStopList **L.
On the other hand, what is passed BN->stopsArray is struct AdjStopList *.
The argument is a pointer to a pointer to AdjStopList, but what is passed is a pointer to AdjStopList.
Therefore, the type differs.
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'm getting the dereferencing pointer to incomplete type error when I try to run the following code. I've checked several other questions about this error and from what I can tell it's not due to a missing or extra struct keyword and I believe the pointer type is correct but I could be mistaken.
There might be other issues with the code as I'm just learning C, I'm happy to try and figure them out for myself I just can't seem to track down the issue with the incomplete type error.
Development/C/AI/test/src/test.c: In function ‘compare’:
Development/C/AI/test/src/test.c:10:19: error: dereferencing pointer to incomplete type ‘lrgraph_node {aka struct lrgraph_node}’
if ( strcmp(other->dataType, current->dataType == 0) ) {
test.c
#include "lrGraph.h"
#include <string.h>
int data = 1;
char *dataType = "int";
lrgraph_edge *connected[] = {};
unsigned numEdges = 0;
int compare( lrgraph_node *other, lrgraph_node *current ) {
if ( strcmp(other->dataType, current->dataType == 0) ) {
return (int)other->data - (int)current->data;
}
return -1;
}
int main() {
lrgraph_node *nodeA = lrgraph_createNode((void*)&data, dataType, &compare, connected, numEdges);
lrgraph_printVersion();
}
lrGraph.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lrGraph.h"
struct lrgraph_edge {
float weight;
lrgraph_node *nodeA;
lrgraph_node *nodeB;
};
struct lrgraph_node {
//data can be of any type
void *data;
//string to see if this node can be compared to another node based on data type
char *dataType;
int numEdges;
//comparator function which compares another node to this node
int (*compare)(lrgraph_node *other, lrgraph_node *current);
//array of connected edges
lrgraph_edge *connected[];
};
void lrgraph_printVersion() {
fprintf(stdout, "\nlrgraph version 0.01b\n");
}
lrgraph_node* lrgraph_createNode(void *data, char *dataType, int (*compare)(lrgraph_node* other, lrgraph_node* current), lrgraph_edge *connected[], unsigned numEdges) {
//allocate enough memory for the struct plus each pointer in the array of edges - https://stackoverflow.com/questions/32311269/can-we-have-a-struct-element-of-type-variable-length-array
lrgraph_node *node = malloc(sizeof(lrgraph_node) + numEdges * sizeof(lrgraph_edge));
if (NULL != node) {
node->data = data;
node->dataType = strdup(dataType);
node->compare = compare;
node->numEdges = numEdges;
//initialize each edge in the array
for( unsigned i=0; i < numEdges; i++) {
node->connected[i] = connected[i];
}
}
return node;
}
lrGraph.h
#ifndef LRGRAPH_H
#define LRGRAPH_H
typedef struct lrgraph_node lrgraph_node;
typedef struct lrgraph_edge lrgraph_edge;
lrgraph_node* lrgraph_createNode(void *data, char *dataType, int (*compare)(lrgraph_node *other, lrgraph_node *current), lrgraph_edge *connected[], unsigned numEdges);
void lrgraph_printVersion();
#endif /*LRGRAPH_H*/
"Incomplete type" means the compiler sees you're trying to use a struct type but there is no definition for that struct.
This is fine if you're only using pointers to structs (and is in fact how abstract data types are implemented in C), but if you want to dereference such a pointer, a struct definition must be visible.
In test.c only the contents of lrGraph.h are visible (i.e. typedef struct lrgraph_node lrgraph_node;), but the actual struct lrgraph_node { ... }; definition exists only in lrGraph.c.
Possible solution: Move the struct lrgraph_node { ... } definition into the header. (Alternatively, put the definition of compare into lrGraph.c).
I am trying to implement a generic stack in c using void pointer to point to the data. the structure looks like this
struct record{
void* data;
struct record* previousRecord;
};
where void pointer data is a pointer to the data a stack position will hold. If I implement a push function like this
struct record* push(struct record* tos, void* data){
struct record* newtos = (struct record*)malloc(sizeof(struct record));
newtos->data = data;
newtos->previousRecord = tos;
return newtos;
}
and push a couple of integer pointers and string pointers into the stack, is there any way I can print the values referenced by these pointers. My problem is that I have to specify the data type of value to print in the code if I use a printf function but the values stored in the stack can only be determined at run time
If you want to print a data in the correct format, you must know what is its type.
#include <stdio.h>
enum datatype
{
DATATYPE_STRING, DATATYPE_INTEGER
};
struct record
{
enum datatype type;
void *data;
struct record *next;
};
void print_record(struct record *p)
{
switch (p->type)
{
case DATATYPE_STRING:
printf("%s\n", (char *)p->data);
break;
case DATATYPE_INTEGER:
printf("%d\n", *(int *)p->data);
break;
}
}
With address how would you know the type of data, it can be string or an integer address:
But you can keep an extra field in your record definition about type of value stored in data part, like below:
typedef enum { STRING, INT, CHAR} type;
struct record{
type t;
void* data;
struct record* previousRecord;
};
and write a common print function :
int print(struct record *r){
switch(r->t){
case CHAR: return printf("%c", *((char*)(r->data)));
case INT: return printf("%d", *((int*)r->data));
case STRING: return printf("%s", (char*)r->data);
default: return printf("Error");
}
}
Here is a Project/A book that can be very helpful to write generic code in C.
I have a tree structure. The nodes would have a leaf node type and internal node type, so I defined these structures, so the internal node would be able to point to either internal nodes or leaf nodes. However, I am having trouble in accessing the child pointers, how can I do that, after all does my code make sense at all?
typedef struct leaf_node_t {
int type;
int key;
int *data_ptr[2]; //This will point to real data.
} leaf_node_t;
typedef struct internal_node_t {
int type;
int key;
typedef union{
struct internal_node_t* iptrs[2];
leaf_node_t* lptrs[2];
} node_ptr;
} internal_node_t;
The typedef of node_ptr does not actually add a field to its enclosing struct. The following adds the fields first, and then follows up with the typedef. The other change I made was having the union represent a single pointer, leaving it to the struct that uses it to decide how many pointers it wants.
typedef struct internal_node_t{
int type;
int key;
union node_ptr_t {
struct internal_node_t* iptr;
leaf_node_t* lptr;
} node_ptr[2];
}internal_node_t;
typedef union node_ptr_t node_ptr_t;
Try this:
typedef struct leaf_node_t{
int key;
int *data_ptr[2];//this will point to real data
} leaf_node_t;
struct internal_node_t;
typedef union{
struct internal_node_t* iptrs[2];
leaf_node_t* lptrs[2];
} node_ptr;
typedef struct internal_node_t{
int key;
node_ptr node;
} internal_node_t;
int main()
{
internal_node_t inode;
leaf_node_t* leaf_node = inode.node.lptrs[0];
return 0;
}
Alternately, if you don't actually need to use the union typedef anywhere else:
typedef struct leaf_node_t{
int key;
int *data_ptr[2];//this will point to real data
}leaf_node_t;
typedef struct internal_node_t{
int key;
union{
struct internal_node_t* iptrs[2];
leaf_node_t* lptrs[2];
}node_ptr;
}internal_node_t;
int main()
{
internal_node_t inode;
leaf_node_t* leaf_node = inode.node_ptr.lptrs[0];
return 0;
}
You should add a flag in the internal_node to know what is the node_ptr, if it's an internal_node_t or a leaf_node_t. Probably a int isInternal[2]; (after the key and before the typedef). if it's 0 the it's internal, if it's 1 then it's leaf_node_t. C language doesn't have a typeof or a GetType to know what type of memory is pointed by a pointer (and C++ has it only if you are compiling with the RTTI "option" activated)