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)
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.
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).
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.
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
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;
}
Related
I must write a function DeleteList() that takes a list, deallocates all of its memory and sets its head pointer to NULL (the empty list).
It seems to work, but idk if it truly works because the way in which I implemented (which I assume is the wrong way) is very different than the one in the solution. I assume it only deletes a few nodes or there is an issue with the memory management.
int Length(struct node* head)
{
int count = 0;
struct node* current = head;
while (current != NULL)
{
count++;
current = current->next;
}
return(count);
}
void DeleteList(struct node** headRef)
{
int len = Length(*headRef);
for(int i = 0;i<len;i++)
free(*headRef);
*headRef = NULL;
}
You are not actually freeing the whole linked list but you are freeing head node repeatedly. I would suggest you to use below approach.
void DeleteList(struct node** headRef) {
struct node *ptr = *headRef;
struct node *temp = NULL;
while(ptr)
{
temp = ptr;
ptr = ptr->next;
free(temp);
}
*headRef = NULL;
}
I've been trying for some time now to make my pop() function work properly but some strange reason all it does is... nothing.
Here is my Stack declaration & function.L.E. I also added the push function.
typedef struct node
{
int v;
struct node* next;
}Node;
void push(Node **l,int val)
{
Node *p = (Node *)calloc(1,sizeof(Node));
p->v = val;
Node *aux=*l;
if(aux == NULL)
{
*l = p;
return;
}
while(aux->next != NULL)
aux = aux->next;
aux->next = p;
}
void pop(Node **l)
{
if(*l != NULL)
{
Node *aux,*prev;
prev = *l;
aux = prev->next;
if(aux == NULL)
free(prev);
else
{
while(aux->next != NULL)
{
prev = aux;
aux = aux->next;
}
prev->next = NULL;
free(aux);
}
}
}
And I call it with
Node *stack = NULL;
pop(&stack);
It would help to see how you push items onto the stack. If you're really calling pop without a push first, well, then it's not supposed to do anything, is it?
This bit makes me nervous:
Node *aux,*prev;
prev = *stack;
aux = prev->next;
if(aux == NULL)
{
free(prev);
return;
}
You set prev to *stack, and if nothing follows prev, you free it. Note that since prev == *stack, you've also freed *stack, so that pointer is now invalid. If you try to access that pointer in your caller, you'll invoke Undefined Behavior.
It looks like you're making your list tail the top of the stack; I'm going to tell you right now that you will make your life much simpler if you make the list head the top of the stack, such that your pushes and pops look like the following:
bool push( Node **l, int val )
{
Node *p = calloc( 1, sizeof *p );
if ( p )
{
p->v = val;
p->next = *l; // set p to point to the current head of the list
*l = p; // make p the new head of the list
}
return p != NULL; // will return false if the calloc (and by extenion,
} // the push operation) fails.
bool pop( Node **l, int *v )
{
Node *p = *l; // p points to head of list
if ( !p )
return false;
*v = p->val; // get value in current node
*l = p->next; // make the next element the new list head
p->next = NULL; // sever the old list head
free( p ); // and deallocate it
return true;
}
No list traversals, no need to keep track of current and previous nodes. All you care about is the head node. The statement p->next = NULL; isn't strictly necessary since we immediately free p afterwards. I like it because it makes it obvious that we have removed p from the list, but if you don't want to spare the cycles, you can omit it.
Edit
I was right to be nervous about that code.
So here's basically what's happening - when you have exactly one item in the stack, you free the head of the list, but you don't update the value of the list pointer (*stack in the original code, *l in the latest edit). The value of the stack variable in main is unchanged, and now it's invalid - the memory at that address is no longer allocated. So the next time you call push, it sees that *l is not NULL, and attempts to traverse down the (non-existent) list.
At this point the behavior is undefined; literally anything can happen. On my system after the first push, stack has the value 0x501010. I do a pop, which frees that memory, but doesn't change the value of stack. On the next push, *l is not NULL, so I set (*l)->next to whatever malloc returns, which in my case is...0x501010 again. So *l is 0x501010, and (*l)->next is 0x501010. If I try to push another item, I wind up in an infinite loop (p == p->next).
To fix this, you need to set the list pointer to NULL after you free it:
Node *aux,*prev;
prev = *l;
aux = prev->next;
if(aux == NULL)
{
free(prev);
*l = NULL;
return;
}
Below is my node struct declaration and my insert at the back function. In main, I declare a head node and point it to NULL. Then I call the function, and try to print out the value of the first node but my program stops. I still can't figure out what is wrong.
typedef struct node {
int val;
struct node *next;
} NODE;
void insert_back(NODE *head, int val) {
NODE *new = malloc(sizeof(NODE));
new->val = val;
new->next = NULL;
if (head == NULL)
head = new;
else {
NODE *p = head;
while (p->next != NULL)
p = p->next;
p->next = new;
}
}
int main() {
NODE *head = NULL;
insert_back(head, 2);
printf("%d", head->val);
}
The pointer which you allocate in insert_back is lost when you get out of your function. In order for this to work, your insert_back should get pointer-to-pointer.
typedef struct node {
int val;
struct node *next;
} NODE;
void insert_back(NODE **head, int val) {
NODE *new = malloc(sizeof(NODE));
new->val = val;
new->next = NULL;
if (*head == NULL)
*head = new;
else {
NODE *p = *head;
while (p->next != NULL)
p = p->next;
p->next = new;
}
}
int main() {
NODE *head = NULL;
insert_back(&head, 2);
printf("%d", head->val);
}
You need to pass the address of the head and not just head. Instead of call by value use call by reference
should be something like insert_back(&head, 2);
And in definition change to void insert_back(NODE **head, int val) {
C passes everything by value. You're passing head, which is a null-pointer (as in value NULL) to the insert_back function.
This NULL is assigned to the head argument-variable of that value.
You're altering that variable, which is local to the insert_back function, which is fine, but don't expect to be altering the variable in the main function, too.
There's 2 possible approaches:
Either add a second level of indirection (pass a pointer to the variable you want to alter), or return the head variable, and reassign:
pointer-to-pointer:
void insert_back(NODE **head, int val)
{
NODE *node = malloc(sizeof *node);
if (node == NULL)//check if malloc was successful!
exit(1);//or fprintf(stderr, "message"); and handle the issue
node->val = val;
node->next = NULL;
if (*head == NULL)
{
*head = node;
return;
}
NODE *tmp = *head;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = node;
}
Call this function as you are doing now, but pass the address of the pointer, rather than the pointer itself:
NODE *head = malloc(sizeof *head);
if (head == NULL) exit (1);
head->next = NULL;
insert_back(&head, 123);
Returning head:
NODE * insert_back(NODE *head, int val)
{
NODE *node = malloc(sizeof *node);
if (node == NULL) exit (1);
node->val = val;
node->next = NULL;
if (head == NULL)
{
return node;//head is null, no need to assign
}
NODE *tmp = head;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = node;
return head;//return node passed initially, because it will be reassigned!
}
//call like so:
head = insert_back(head, 123);
As an added bonus, you can use this function to allocate a new struct, too:
NODE *head = insert_back(NULL, 123);//pass null pointer, will return new node and assign it to head
But, equally valid:
NODE *head = insert_back(NULL, 123);
head = insert_back(head, 456);
head = insert_back(head, 789);
printf("Head: %d\nNext: %d\nTail: %d\n",
head->val,
head->next->val,
head->next->next->val
);
Of course, don't forget to write a decent function to free your linked lists.
Perhaps, if you haven't written this already, here's a basic example (again: both methods can be used, but I'd recommend the pointer-to-pointer approach):
void free_list(NODE **list)
{
if (*list->next == NULL)
{//tail
free(*list);
*list = NULL;//assign NULL, makes a valid NULL pointer
return;
}
free_list(&(*list->next));//recursive call
//once we get here, all next-nodes are freed:
free(*list);//free node, and again:
*list = NULL;//make a valid null pointer
}
//call:
free_list(&head);
free(head);//will not be a problem, head is NULL pointer
Alternatively:
void * free_list(NODE *list)
{//note VOID POINTER is returned (will always return NULL, though)
if (list->next == NULL)
{
free(list);
return NULL;
}
free_list(list->next);
free(list);//free node, and again:
return NULL;//make a valid null pointer
}
//call
head = free_list(head);
free(head);//not an issue here
So both are equally safe, you might think, but what if you forget to assign the return value of the second free_list function?
free_list(head);
free(head);//<--X undefined behaviour
The memory head points to has already been freed, but you're calling free a second time. That's going to give you grief: the head pointer is invalid, passing an invalid pointer to free results in undefined behaviour. That's why the first (pointer-to-pointer) approach is the safer option: The function, once written, will never forget to assign NULL to the pointer.
As an asside, a couple of tips:
your main function doesn't return an int. compile this code with -Wall and fix that issue by adding a return 0; statement.
Check the return value of all functions, including malloc & co, if the allocation failed, it will return NULL. You're not checking for that, so there is a risk of undefined behaviour there.
Well basically I had memory leaks. So I wanted to fix them! added free () in some functions. Run valgrind and got successful message All leak memories fixed or smth like that! And after that I have got bunch of errors :( I THINK i have put free() right. It is easy to get confused because there are node as a pointer and node as a struct (look in file.h). Any help appreciated. Thank you. Sorry if this question is simple. i am beginner.....
code in file.h
struct node {
int value;
struct node * next;
};
typedef struct node List;
int is_empty(List *);
List *add_node(List *, int);
List *remove_node(List *, int);
List *create_node(int);
char *tostring(List *);
code in file.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
#define STRSIZE 128 /*assume string representation fits*/
/* Return true if the list h is empty
* and false otherwise.
*/
int is_empty(List *h) {
return h == NULL;
}
/* Create a list node with value v and return a pointer to it
*/
List *create_node(int v) {
List *node = malloc(sizeof(List));
free(node);
node->value = v;
node->next = NULL;
return node;
}
/* Insert a new node with the value v at the
* front of the list. Return the new head of
* the list.
*/
List *add_node(List *h, int v) {
List *node = create_node(v);
node->next = h;
return node;
}
/* Remove the first node in the list h that
* has the value v. Return the head of the
* list.
*/
List *remove_node(List *h, int v) {
List *curr = h;
/* Handle the cases when list is empty or the value
* is found at the front of the list */
if (h == NULL) {
return h;
} else if (h->value == v) {
h = h->next;
return h;
}
/* Look for the value in the list (keeping the pointer to
* the previous element so that we can remove the right
* element) */
while (curr->next != NULL && curr->next->value != v) {
curr = curr->next;
}
if (curr->next == NULL) { /* v is not in list so do nothing */
return h;
} else { /* curr->next->value == v */
curr->next = curr->next->next;
return h;
}
}
/* Return a string representation of the list pointed to by h.
*/
char *tostring(List *h) {
char *str= malloc(STRSIZE);
char num[4]; /* assume integer has max. four digits*/
free(str);
str[0] = '\0';
while (h != NULL) {
sprintf(num, "%d", h->value);
strncat(str, num, STRSIZE - strlen(str) - 1);
h = h->next;
}
return str;
}
Possibly you want
temp = curr->next;
curr->next = curr->next->next;
free (temp);
In the current state of your code the remove_node is leaky (leaks the entire list actually, if you remove all the nodes).
Also, to stop memory leak in the tostring function, the caller of this function has the responsibility to free the string returned by tostring.
In your create_node(), why do you have a free()? You should remove that free().
In your remove_node(), you need to always return the head. I think the following recursive method should work. The recursive function will find the node to be deleted and return the next node. It returns the same node if nothing is deleted. Keeps recursing until a node with the value is found or end of the list. The main thing to check is, does it work when
Removing the head node
empty list
Removing the last node
Removing a middle node
The following code is not tested :-).
You mentioned you still have memory leak. As mentioned by Karthik, your toString() function allocates memory and it is up to the caller to free it. So make sure every time you call toString() function, a free() is called also. Otherwise you would be leaking memory.
List *remove_node(List *h, int v) {
List *retval = remove_recurse(h,v);
// if retval is different from head, means head is removed. return new head.
// Otherwise return old head.
return (retval!=h) ? retval : h;
}
List *remove_recurse(List *node, int v) {
if(node==NULL) return NULL;
List *retval = node; // default return current node
if(node!=NULL && node->value==v) { // need to remove node
retval = node->next; // return the next node
free(node); // delete node
}
else {
List *temp = remove_recurse(node->next,v);
// if next node was deleted, point to new node
if(node->next!=temp) node->next=temp;
}
return retval;
}
With this
List *node = malloc(sizeof(List));
free(node);
you allocate a node(List) then let node point to it, then you free what node is pointing to so after free it is pointing to some unallocated space somewhere in memory then you start assigning to that memory:
node->value = v;
node->next = NULL;
which causes undefined behavior, it is definitely wrong but will not be detected by the compiler.
remove free(node)
List *create_node(int v)
{
List *node = malloc(sizeof(List));
node->value = v;
node->next = NULL;
return node;
}
it is more readable if you keep the name of the struct the same as the typedef i.e.
typedef struct node {...} node;
instead of creating a new alias, use instead a better variable name e.g.
node* listStartOfNodes = NULL; // always initialize
1、this function is wrong.
List *create_node(int v) {
List *node = malloc(sizeof(List));
free(node);
node->value = v;
node->next = NULL;
return node;
}
Why do you free(node)? please remove this free(node);.
And the same fault in this function, please remove free(str);
char *tostring(List *h) {
char *str= malloc(STRSIZE);
char num[4]; /* assume integer has max. four digits*/
free(str);
str[0] = '\0';
while (h != NULL) {
sprintf(num, "%d", h->value);
strncat(str, num, STRSIZE - strlen(str) - 1);
h = h->next;
}
return str;
}
2、you should modify this function:
List *remove_node(List *h, int v) {
List *curr = h;
List* freeNode = NULL;
/* Handle the cases when list is empty or the value
* is found at the front of the list */
if (h == NULL) {
return h;
} else if (h->value == v) {
freeNode = h;
h = h->next;
free(freeNode);
return h;
}
/* Look for the value in the list (keeping the pointer to
* the previous element so that we can remove the right
* element) */
while (curr->next != NULL && curr->next->value != v) {
curr = curr->next;
}
if (curr->next == NULL) { /* v is not in list so do nothing */
return h;
} else { /* curr->next->value == v */
freeNode = curr->next;
curr->next = curr->next->next;
free(freeNode);
return h;
}
}
In the function remove_node
List *remove_node(List *h, int v)
{
List *curr = h,*prev;
/* Handle the cases when list is empty or the value
* is found at the front of the list */
if (h == NULL) {
return h;
} else if (h->value == v) {
h = h->next;
free(curr);
return h;
}
while (curr->next != NULL && curr->next->value != v) {
curr = curr->next;
}
if (curr->next == NULL) { /* v is not in list so do nothing */
return h;
} else { /* curr->next->value == v */
prev = curr->next;
curr->next = curr->next->next;
free(prev);
return h;
}
}
You should free the memory when you no longer want that node in your case while removing the node you should free the memory.
And in the function tostring don't free the memory you just allocated free the memory in the called function after the str is no more used or required.
was implementing a singular linked list in C.
struct node
{
int data;
struct node *next;
};
struct list_el {
int val;
struct list_el * next;
};
typedef struct list_el item;
void main() {
item * curr, * head,*track;
int i;
head = NULL;
for(i=1;i<=10;i++) {
curr = (item *)malloc(sizeof(item));
curr->val = i;
curr->next=0;
if(head!=NULL)
head->next = curr;
head = curr;
}
curr = curr-10;
while(curr) {
printf("%d\n", curr->val);
curr = curr->next ;
}
}
As there are 10 elements in the list, so to make the pointer point to the first element, I tried decreasing curr (pointer to struct) by 10, but this got me half way through the list, the values printed were 5,6,7,8,9,10.
The size of the struct is 4, whereas the size of the pointer is 2, it seems the pointer is decreased by 2*10=20 bytes instead of 40, is this normal? (as I read that pointer increments/decrements according to the size of its type)
You cannot use pointer arithmetic on a linked list: the items are allocated separately (with malloc) and so they will not be necessarily adjacent in memory. That approach would only work with an array.
There are several problems.
First of all, the following insertion code isn't correct:
if(head!=NULL) head->next = curr;
head = curr;
Basically, the element pointed to by head is irrevocably lost.
Secondly, the behaviour of the following code is undefined:
curr = curr-10;
You cannot move across several malloc()ed blocks using pointer arithmetic.
Once you fix the insertion logic, it will become possible to traverse the list like so:
for (curr = head; curr != NULL; curr = curr->next) {
....
}
Your code curr = curr-10 will not bring you back to the head of the linklist.
As Viruzzo pointed out in a comment, you cannot use pointer arithmetic on elements of a linked list. As the word "linked" implies, there are only pointers linking the items together, they're not required to be located at adjacent addresses.
The pointer arithmetic will simply decrease the pointer by a fixed number of bytes, it will not follow pointers. Your list, being singly-linked, doesn't even have previous-element pointers to follow.
curr = curr-10; is wrong. It does not perform the operation that you think it does!
To print the contents of your linked list, you need to start from the head and go through each and every node until you hit NULL (assuming its not a circular list).
void display()
{
NODE * current = head;
if (current == NULL) {
printf("Empty list \n");
return;
}
while(current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
return;
}
And to add new node in the front, you can use the following code snippet.
void addfront(int data)
{
NODE *newnode = NULL;
if ((newnode = malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("Couldn't allocate space for new element \n");
return;
}
if (head == NULL) {
// empty list
head = newnode;
tail = newnode;
} else {
newnode->next = head;
head = newnode;
}
return;
}
To add new node at the rear, you can use the following code snippet.
void addrear(int data)
{
NODE * newnode = NULL;
if ((newnode = (NODE *) malloc(sizeof(NODE))) != NULL) {
newnode->data = data;
newnode->next = NULL;
} else {
printf("unalbe to allocate memory to the new element - %d \n", data);
return;
}
if (tail == NULL) {
assert(head == NULL && tail == NULL);
head = tail = newnode;
} else {
tail->next = newnode;
tail = newnode;
}
return;
}
All the above mentioned code snippet assumes, you have head and tail as global variables.
Hope this helps!