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;
}
Related
This method is supposed to append a Node at the end of a linked list. The method loops until it reaches the end, which is the null pointer. But when I try to change the null pointer to a value, it crashes. How should I fix this? (The Node pointer has a integer data and another Node variable which the current Node points to).
void appendItem(LinkedList* list, int value)
{
Node* temp = (Node*)malloc(sizeof(Node));
temp = list->head;
while(temp != NULL)
{
temp = temp->next;
}
temp->data = value;
temp->next = NULL;
}
Dereferencing NULL is prohibited.
Instead of that, you should manage a pointer to what should be changed.
Also note that allocating some buffer via malloc() and overwriting the result with another value just after that causes a memory leak.
One more point is that casting results of malloc() family is considered as a bad practice.
Fixed code:
void appendItem(LinkedList* list, int value)
{
Node** temp = &list->head;
while(*temp != NULL)
{
temp = &(*temp)->next;
}
*temp = malloc(sizeof(Node));
if (*temp != NULL)
{
(*temp)->data = value;
(*temp)->next = NULL;
}
}
These lines
Node* temp = (Node*)malloc(sizeof(Node));
temp = list->head;
produces a memory leak. At first a memory was allocated and its address was stored in the pointer temp and then the value of the pointer temp was overwritten by the value of the expression list->head. As a result the address of the allocated memory was lost.
After this loop
while(temp != NULL)
{
temp = temp->next;
}
the pointer temp is equal to NULL. So a null pointer is used to access memory in these statements
temp->data = value;
temp->next = NULL;
that invokes undefined behavior.
The function can be defined for example the following way.
int appendItem( LinkedList *list, int value )
{
Node *new_node = malloc( sizeof( Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = value;
new_node->next = NULL;
if ( list->head == NULL )
{
list->head = new_node;
}
else
{
Node *current = list->head;
while ( current->next != NULL ) current = current->next;
current->next = new_node;
}
}
return success;
}
Pay attention to that the memory allocation can fail. You need to process such a case in your function. And the caller of the function should be informed about such a situation.
Also as you allow to append new nodes to a singly-linked list then the list should be defined as a two-sided singly-linked list. That is the list should keep two pointers: one pointer to the head node and other pointer to the tail node. Otherwise appending a node to the list will be inefficient.
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;
}
In the below piece of code, I am able to modify the a variable used in main from the function.
#include<stdio.h>
int main()
{
int *a,b=10;
a = &b;
printf("%d\n",*a);
ref(a);
printf("%d\n",*a);
return 1;
}
int ref(int *a)
{
int b = 98;
*a = b;
return 1;
}
whereas, in the below piece of code, I couldnot able to do the same.
I know that we can modify a value which is in the main, from a function by using double pointer. I also know that we can use single pointer to modify, by returning the required address to the main and getting it in the main with the same data type. I just wanted to know whether I can modify a value in the main by passing it as a parameter to the function, only as a single pointer to the (structure) variable.
Note: I have denoted the working code with the comment '//WC'. Will be very thankful if someone can explain me the same.
//int insert(int data, Node **head) //WC
int insert(int data, Node *head)
{
Node *temp, *run;
temp = (Node *) malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
//if(*head == NULL) //WC
if(head == NULL)
{
printf("1st node\n");
//*head = temp; //WC
*head = *temp;
}
else
{
printf("node after first\n");
//run = *head //WC
*run = *head;
while(run->next != NULL)
{
run = run->next;
}
run->next = temp;
}
return 1;
}
int main()
{
Node *head;
insert(10, head);
insert(20, head);
insert(30, head);
insert(40, head);
insert(50, head);
return 1;
}
How can I pass a single pointer to a structure, inside a function and modify that structure variable?
TL;DR : you can modify the value pointed by the pointer, but you cannot modify the passed pointer itself.
C uses pass-by-value for function parameter passing. You cannot change the value of the received parameter from the called function and expect it to reflect in the variable used as the argument from the caller function.
However, in case of pointers, you usually don't modify the pointer itself, rather, we modify the value it points to. So, the changed value pointed by that pointer will be reflected in the caller function.
When you check if head is empty (has NULL value), you need to check the content of head (*head), not head itself since that means its own address. so if (head == NULL), should be *head == Null. head represents memory address of the pointer head and *head represents what is saved in that address(what is pointed to). With that logic, *head = temp; is correct as it will save the address of the dynamically allocated memory address -temp in head however the later one (*head = *temp) will attempt to copy/save content of temp to head which doesn't make sense since head is has only a size of a pointer and temp could be allocated whatever size the node is. I hope I helped at least a little bit and here is a working version of your code :)
int insert(int data, Node **head) //WC, This is correct because the parameter **head takes address of the pointer to the first node if any.
//int insert(int data, Node *head)
{
Node *temp, *run;
temp = (Node *) malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
if(*head == NULL) //WC, checking if head has any address value inside (not its own address)
{
printf("1st node\n");
*head = temp; //WC, because temp has address of the allocated memory and you wanna hold that address as the head / first node.
}
else
{
printf("node after first\n");
run = *head //WC
//*run = *head; you can't use this, one reason is because head could point to any size of memory (e.g 10000kb) and run has a size of a pointer, just few bytes.
while(run->next != NULL)
{
run = run->next;
}
run->next = temp;
}
return 1;
}
(Edit: multiple pointer use might complicate reading so I'd rather use the following struct defination)
typedef struct node* PNode; //Pointer to node
typedef struct node {
int item;
Pnode next;
} Node;
void insert(int data, PNode *head) {
PNode temp, run = *head;
temp = (PNode)malloc(sizeof(Node));
temp->data = data;
temp->next = NULL;
if (run == NULL){
*head = temp;
}//first node
else{
while (1) {
if (run->next == NULL) {
run->next = temp;
break;
}
run = run->next;
}
}
}
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.
I am trying to learn C, and as many people, I have been a little stuck with pointers. Anyways, I made a recursive function that destroys my linked list, but as I have debugged, when I am back from the function the head of the list is not null as it should be, so I'm guessing it's some basic misunderstanding with pointers. Here's the function:
void destroy(struct node *n) {
if (!n) return;
destroy(n->next);
free(n);
n = NULL;
}
void deleteList(struct node** head_ref)
{
struct node* current = *head_ref;
struct node* next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
*head_ref = NULL;
}
Try like this ....you can change names as you want. If you still need help let me know.
Head has been freed when this functions ends but it's not null. Everything in C is passed by value. So you pass a copy of the location of head into destroy. That memory is deallocated but head is not changed.
You could write this as:
destroy(&head);
void destroy(struct node** n){
if(!*n) return;
destroy(&((*n)->next));
free(*n);
*n = NULL;
}
You have to use a pointer pointing to your list, calling with destroy(&n):
// clear complete list
void destroy(struct node **n)
{
if (*n == NULL)
return;
if ((*n)->next == NULL)
{
free(*n);
*n= NULL;
return;
}
struct node *iter = *n;
struct node *prev = NULL;
// get last item and the previous one
while (iter->next != NULL)
{
prev = iter;
iter = iter -> next;
}
prev->next = NULL;
free(iter);
destroy(n);
}
Hope this may help you.
Your recursive destroy function cannot modify the head variable in the caller's frame.
The statement n = NULL only affects the function argument, which is a local variable of the destroy function. It actually has no effect, so you can remove this statement.
You should set the head to NULL after the call to destroy in the caller function if it is needed there.
Here is the sample function to destroy Linked list using DeleteRear():
void Destroy_Using_Rear(List *L)
{
int y;
Node *P,*Q,*Z;
while(P!=NULL){
y=DeleteRear(L,x);
return y;
Z=P;
P=*L;
}
}