C beginner. I'm trying to implement a graph, and I have these structs:
typedef struct GraphNode{
void *key;
void *data;
void **edges;
} GraphNode;
typedef struct Graph {
int nodes_count;
void **nodes_list;
void **edges_list;
} Graph;
The Graph struct is basically just holding two arrays with all the nodes and edges added so far. It also has nodes_count which I want to increment each time I add a node. I want each GraphNode struct to have a key, data, and an array of all connecting edges.
I have an insert function:
int Graph_insert(Graph *map, void *key, void *data)
{
GraphNode *node = Graph_node_create(key, data);
map->nodes_count++;
/** add node to map->nodes_list here **/
}
Which uses Graph_node_create:
GraphNode *Graph_node_create(void *key, void *data)
{
GraphNode *node = calloc(1, sizeof(GraphNode));
node->key = key;
node->data = data;
node->neighbors = calloc(DEFAULT_MAX_NEIGHBOR_COUNT, sizeof(Edge *));
return node;
}
The issue is when I call Graph_node_create. It seems to be creating a GraphNode *node and returning it, but after doing so map->nodes_count is messed up and shows a nonsense value. If I change the functions slightly and pass the Graph *map to Graph_node_create for the sole purpose of tracking map->nodes_count, and then print map->nodes_count like so:
GraphNode *Graph_node_create(Graph *map, void *key, void *data)
{
GraphNode *node = calloc(1, sizeof(GraphNode));
printf("map->nodes_count: %d\n", map->nodes_count);
node->key = key;
printf("map->nodes_count: %d\n", map->nodes_count);
...
}
I get the following when running a unit test:
RUNNING: ./tests/graph_tests
map->nodes_count: 0
map->nodes_count: 73081008
It seems like whatever is happening is happening when first assigning the passed key to node->key, but I can't figure out why. It seems like some memory is being overwritten or something. Any help would be greatly appreciated.
(For the sake of completeness here is the Edge struct. I don't think its pertinent to the question tho.)
typedef struct Edge {
GraphNode *from;
GraphNode *to;
int weight;
} Edge;
This is mostly tangential to your main problem (but it's too long to fit in a comment).
You should revise your code to avoid void * or void ** values, at least for the lists of nodes and edges. You should also count both the nodes and the edges. You can forward declare your structure types so that you can use their names accurately:
typedef struct GraphNode GraphNode;
typedef struct Graph Graph;
typedef struct Edge Edge;
struct GraphNode
{
void *key;
void *data;
size_t edges_count;
Edge **edges;
};
struct Graph
{
size_t nodes_count;
size_t edges_count;
GraphNode **nodes_list;
Edge **edges_list;
};
struct Edge
{
GraphNode *from;
GraphNode *to;
int weight;
};
None of this explains why you're running into problems with calloc(). However, part of the trouble could be tracking the levels of indirection accurately.
For example, you must have allocated the key and the data so that you can store those pointers in the graph — and you must not free those values until you release the graph. Using the Edge **edges; means you will allocate an array of pointers, and then fill those pointers in. You might need two values for the number of edges in a graph node — one for the number of pointers allocated (sometimes called the capacity) and one for the number of edges stored. I often use names like edges_max and edges_num (or max_edges and num_edges) for the two elements. Similar comments apply to the lists in the graph structure. It isn't clear how you're keeping track of all this.
Related
In my adventures implementing generic data structures in C, I've come across a dilemma. For example, in the following code:
void add_something(avl_tree_t * my_tree) {
int new_element = 123;
avl_insert(my_tree, (void*)&new_element);
}
int main() {
avl_tree_t * my_tree = avl_create();
add_something(my_tree);
// do stuff
avl_print(my_tree, function_that_prints_ints);
exit(0);
}
In which avl_insert is defined as
void avl_insert(avl_tree_t * tree, void * data) {
avl_node_t * new_node = malloc(sizeof(struct avl_node));
new_node->data = data;
// do tree balancing stuff
}
In order for my generic insertion function to work, I have to pass it a void * item to store. However, in order for that to work, in this case I need to pass in the address of the new int item I'm adding so that I can then dereference it to a void *. If I am not mistaken, when we're back in the main function, the memory address in which I stored my new element will be compromised.
One way I looked into to solve this issue is to pass in the size of the things I am storing in the tree as a parameter for avl_create, and then allocating memory for a copy of each element I insert. This works because you don't need the original address or value for whatever you added.
Another thing that works is only using the data structure in the span of a single function, which is obviously not viable.
My question is this: what is the best way to go about storing statically allocated data in a generic data structure, be it basic C types or user made structures?
Thank you in advance.
To store pointers to data with automatic storage duration, yes, you would have to know the size of the elements in the container and allocate and copy the pointed-to data.
The simplest way is to just allocate and copy in all cases, optionally using a user-specified clone() or create() function to make deep copies, if necessary. This also entails the use of a user-specified destroy() function to dispose of the copies properly (again, if necessary).
To be able to avoid the allocation, then you have to have some kind of state variable that lets you know if the container should allocate, or just copy the pointer value itself.
Note that this should apply to the container object, not to the individual nodes or elements. If a container stores data in one way or the other, it should store all data that way. See Principle of Least Astonishment.
This is the more complex approach, since you have to be sure to use the correct process for adding and deleting elements based on the state variable. It's ususally much simpler to just make sure you never pass in a pointer to a value with automatic storage duration.
Use a mix-in style; e.g. do not make data part of the node but the node part of the data:
struct avl_node {
struct avl_node *parent;
struct avl_node *left;
struct avl_node *right;
};
struct person {
char const *name;
struct avl_node node;
};
struct animal {
struct avl_node node;
int dangerousness;
};
Constructors for animal are like
struct animal *animal_create(double d)
{
struct animal *animal = malloc(sizeof *animal);
*animal = (struct animal) {
.node = AVL_NODE_INIT(),
.dangerousness = d,
};
return animal;
}
The generic AVL tree operations could look like
void avl_tree_insert(struct avl_node **root, struct avl_node *node,
int (*cmp)(struct avl_node const *a, struct avl_node const *b))
{
/* .... */
}
and a cmp function for animal like
int animal_cmp(struct avl_node const *a_, struct avl_node const *b_)
{
struct animal const *a = container_of(a_, struct animal, node);
struct animal const *b = container_of(b_, struct animal, node);
return a->dangerousness - b->dangerousness;
}
A uni project I have involves sorting a very large set of data into two different lists, one which has a bunch of data on a city or country, and another which has that same data (on a city, this time), but also with some coordinates, like so:
//used for cities and countries in the textual mode
typedef struct node{
int year;
int month;
float temp;
char* name;
struct node* next;
struct node* prev;
} node_t;
//used for cities in the graphical mode
typedef struct City{
node_t data;
float latitude;
float longitude;
} City;
That is the way I set this up, but it doesn't allow me to use the same functions, because the pointers I have are to 'node', not 'City'. I could make them both like the second one, but putting half a million entries in memory, each with two empty floats would be kind of unnecessary and problematic.
I'm looking to use the same functions for both of them. The functions are your usual linked list ones, like sorted insertion and such. I was trying to use void pointers before, casting them as needed, but that means my functions must have two parts to them.
I'm looking to change the uhh... structure of my structs, so that they allow me to use the same functions simply, without the need for casts, or with a minimal one at least.
They are quite similar as you can see, but nothing comes to mind. Any ideas would be greatly appreciated. Cheers!
You could modify your linked list implementation to use void* as a data pointer.
struct Node
{
void *data;
struct Node *next;
}
The insert function should look something like:
Node * insert (struct Node *h, void *data, size_t data_size)
{
Node *node = malloc(sizeof(Node));
node->data = malloc(data_size);
memcpy(node->data, data, data_size);
node->next = h;
h = node;
return h;
}
When inserting City or any other type:
City* city = malloc(sizeof(City));
insert(head, city, sizeof(City));
I'm not sure how specific I have to be but I'll give the breakdown best I can. I'm taking a typedef struct:
typedef struct {
char name[21];
int life;
} pcb_t;
inputting values for the name & life, then storing it in a doubly linked-list.
the linked-list structs in the header file are:
typedef struct list_node {
void *data;
struct list_node *next;
struct list_node *prev;
} List_node_t;
typedef struct {
List_node_t *head;
List_node_t *tail;
} List_t;
In my main I have the first struct variables initialized as:
char name[BUF_MAX];
int life;
pcb_t *pcb;
The input is all correct and the pcb struct is stored as a new node in the list. I tried to run a simple loop after the initial input to print out the Name & Lifetime values for each of the pcb structs. The loop I used is this:
void *context = NULL;
void *data;
while( List_next_node( &the_list, &context, &data) && (data != NULL))
{
printf("Name: %s\n", (char *)data);
printf("Lifetime: %d\n", (int )data);
}
Where the List_next_node function transverses the list. the_list is the list, context is what keeps track of where we are in the list, and data is the data.
I'm not sure how to access the information I want as my while loop correctly prints out the Name of the pcb struct, but the lifetime is not.
Lists, doubly linked or otherwise, are a complete red herring, here. The issues are (1) accessing struct members, which hopefully is trivial; and (2) doing that when all you have is a void *, which is possibly a little less intuitive.
This is the simplest way:
void *data;
while( List_next_node( &the_list, &context, &data) && (data != NULL))
{
pcb_t * current_data = data;
printf("Name: %s\n", current_data->name);
printf("Lifetime: %d\n", current_data->life);
}
The only reason your current code "works" for printing out the name is because name is the first element of your struct, and so the address of name happens to be the same as the address of the whole struct, so when you cast the address of the struct to char * you get the result you're expecting, even though you're not really getting there the right way.
As ojblass's answer shows, you can do it with a cast and avoid the use of a temporary variable, but I think a temporary variable makes things a lot clearer.
printf("Lifetime: %d\n", ( (pcb_t *) data) ->life);
I am trying to create a linked list in C but trying to pack it nicely in somewhat of a C++ style class. I am having some issues however using function pointers in C.
typedef struct linkedList {
int count;
struct msgNode *front;
struct msgNode *back;
void (*addMSG)(unsigned char *, int, struct linkedList *);
} msgList;
void addMSG(unsigned char *data, int size, struct linkedList *self);
Ideally, I would like to have it such that you can make you list and then to add you can simply call a "method"(function) within the structure, simulating behavior you would see in C++.
Currently I get a segmentation fault when I call addMSG, which of-course is because addMSG is not pointing to a function. However, I don't want to have to specify a function to point to every single time I want use a linked list. Is there any nice way to have function pointers without implicitly having to point to the function, or do you have to implicitly point it to the function?
This is only the partial implementation shown here. At the end, this struct will have all the necessary functions. This is just for the sake of keeping this question short and to the point.
You need to assign the function to the member. i also recommend giving them different names:
typedef void (*addMSGFunc)(unsigned char *, int, struct linkedList *);
typedef struct linkedList {
int count;
struct msgNode *front;
struct msgNode *back;
addMSGFunc addMSG;
} msgList;
void addMSGImpl(unsigned char *data, int size, struct linkedList *self)
{
...
}
And then after creating a msgList:
msgList myList;
myList.addMSG = addMSGImpl;
Well you can't add a default value in the declaration of the struct but what you can do is:
Create a function to initialize the linkedList instance - I guess you've seen that in C style libraries
Create a default list item and use that when creating new entities.
Like:
void addMSG(unsigned char *data, int size, struct linkedList *self);
struct linkedList {
int count;
struct msgNode *front;
struct msgNode *back;
void (*addMSG)(unsigned char *, int, struct linkedList *);
} DefaultList = {0, NULL, NULL, addMSG};
You can have an uninitialized function pointer just fine as long as you don't actually use it. If you do want to use it to call a function, then obviously you have to assign a function to it. C is unable to guess which function you want to use.
If you have a linked list structure where sometimes you need a function, and sometimes you don't, then just assign NULL to it when you create the list, and have your list implementation only call the function when it's not NULL.
If it always points to the same function, then just do the assignment in your constructor function.
I am a beginner in programming, please go easy on me and I am finding difficult to get the answer for my question. I can't get my head around the complex codes. Can some one please explain me with simple coding of how is generic list manipulation function written which accepts elements of any kind? Thanks in advance.
This is normally done using void pointers:
typedef struct node {
struct node *next;
void *data;
} node;
node *insert(node *list, void *data) {
}
node *delete(node *list, node *to_delete) {
}
such manipulation functions do not depend on the actual type of data so they can be implemented generically. For example you can have a data type struct for the data field above:
typedef struct data {
int type;
void *data;
} data;
/* .... */
data d;
d.type = INT;
d.data = malloc(sizeof(int));
node n = {NULL, (void*)&data);
It looks like you need a heterogenous list. Some pointers below:
Make the data element of the list node as a generic structure, which contains an indicator for data type and data.
/** This should be your data node **/
struct nodedata
{
int datatype;
void *data;
};
/** This should be your list node **/
struct listnode
{
struct nodedata *data;
struct listnode *next;
};
Using the above structure, you can store different types of data.
Use function pointers for comparison functions or invoke different functions depending upon the data type.