Reputation: 33
Solution in comments.
typedef struct Vertex {
int i;
int color;
} vertex;
typedef struct Edge {
vertex v1;
vertex v2;
} edge;
typedef struct Node {
void *p;
struct Node *next;
} node;
Basically this is a linked list (of nodes). In my program I know if a node array holds edges or vertices.
I'm not sure how to free a list of edges properly, I've tried the following:
static void freeEdgeList(node *list) {
if (list == NULL) return;
node *ptr = list;
node *tmp;
do {
tmp = ptr->next;
free(&((*((edge *)(ptr->p))).v1));
free(&((*((edge *)(ptr->p))).v2));
free(ptr->p);
free(ptr);
} while ((ptr = tmp) != NULL);
}
Because my struct Edge doesn't store pointers, is it enough to free the edge struct, without freeing the vertices stored in the edge? I'm a little confused.
Edit:
static int addEdge(edge *e, node **list) {
if ((*list) == NULL) {
(*list) = malloc(sizeof(node));
if ((*list) == NULL) return -1;
(*list)->p = malloc(sizeof(edge));
if ((*list)->p == NULL) return -1;
memcpy(&((*list)->p), &e, sizeof(edge));
(*list)->next = NULL;
} else {
node *tmp = (*list);
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = malloc(sizeof(node));
if (tmp->next == NULL) return -1;
tmp = tmp->next;
tmp->p = malloc(sizeof(edge));
if (tmp->p == NULL) return -1;
tmp->next = NULL;
memcpy(&(tmp->p), &e, sizeof(edge));
}
return 0;
}
This is the function that adds edges to a list (initially the list passed in is NULL). It seems to add the edges correctly because I can output the list to the console just fine. But if I try to free with:
static void freeEdgeList(node *list) {
while (list) {
node *tmp = list;
list = list->next;
free(tmp->p);
free(tmp);
}
}
I get different error (segfault, invalid pointer)
Upvotes: 0
Views: 3422
Reputation: 33621
As others have mentioned freeEdgeList
needs a fix [so follow their responses].
In addEdge
, your memcpy
calls are incorrect. You are copying to/from the address of a pointer and not what the pointer points to.
You want: memcpy((*list)->p, e, sizeof(edge))
and memcpy(tmp->p, e, sizeof(edge))
Also, in addEdge
, if *list == NULL
, you don't set it to the first/new element.
Also, the code can be simplified a bit. For example, using *list
everywhere is a bit cumbersome.
Here's a refactored version with the memcpy
and *list
bugs fixed:
static int
addEdge(edge *e, node **list)
{
node *head = *list;
node *cur;
node *prev;
int ret = -1;
// find the end of the list
prev = NULL;
for (cur = head; cur != NULL; cur = cur->next)
prev = cur;
do {
// allocate new node
cur = malloc(sizeof(node));
if (cur == NULL)
break;
cur->next = NULL;
// add pointer to new edge
cur->p = malloc(sizeof(edge));
if (cur->p == NULL) {
free(cur);
break;
}
// copy in the edge data
memcpy(cur->p,e,sizeof(edge);
// link in new node
if (prev != NULL)
prev->next = cur;
else
head = cur;
// adjust list pointer
*list = head;
ret = 0;
} while (0);
return ret;
}
Upvotes: 0
Reputation: 224377
You can only pass to free
exactly what was returned from malloc
and family. Since you presumably called malloc
to allocate a node
, you only need to free a node
.
Neither vertex
nor edge
contain fields that are pointers, so there is nothing else to free. All you need to do is:
static void freeEdgeList(node *list) {
while (list) {
node *tmp = list;
list = list->next;
free(tmp->p);
free(tmp);
}
}
EDIT:
In the code where you add an edge, you incorrectly do this:
memcpy(&((*list)->p), &e, sizeof(edge));
...
memcpy(&(tmp->p), &e, sizeof(edge));
Since e
is a edge *
, what this is doing is copying the pointer value e
to the field p
instead of what it points to. That results in the edge
object pointed to by p
having invalid values. You instead want:
memcpy((*list)->p, e, sizeof(edge));
...
memcpy(tmp->p, e, sizeof(edge));
This will copy the values contained in the edge
that e
points to.
Upvotes: 2
Reputation: 33
Edit: Seems I didn't quite get it yet..
Thanks for your help, many thanks! That makes it clear to me.
while (list) {
node *tmp = list;
list = list->next;
free(&(tmp->p));
free(tmp);
}
This solution worked, I needed to pass the address of the pointer to free, not the pointer itself, I don't quite understand why though.
Upvotes: 1
Reputation: 31173
The rule is if you don’t allocate it you don’t free it. The struct Edge
doesn’t contain any dynamic memory allocation or pointers, as you said, so you don’t free them yourself. The memory is allocated as part of Edge
and be freed when you free it.
So remove the free()
s from v1
and v2
and only use free(ptr->p)
.
Upvotes: 1
Reputation: 3915
Yes, it's correct. Since you are not malloc()
ing the vertex
(they aren't pointers, but variables allocated inside the Edge structure) a simple free()
for the Edge structure will suffice
Upvotes: 0