free() function does not clear well my stack - c

Sorry if my code and also English are a bit sketchy.
I am currently trying to print and deallocate the space in which my stack structs were stored with a function which the prototype is void printStack(struct cell *p). It calls also another function which is basically a pop function for stacks (once picked the first element stored in it, the function returns it) (struct cell *pop(struct cell **p)).
The body of both functions are here down below:
struct cell *pop(struct cell **p) {
struct cell *temp;
if(*p == NULL)
return *p;
else {
temp = *p;
*p = (*p)->next;
temp->next = NULL;
return temp;
}
}
void printStack(struct cell *p){
struct cell *popped;
if(p == NULL) {
printf("The stack is empty\n");
} else {
while(p != NULL) {
popped = pop(&p);
if(popped != NULL) {
printf("Value popped: %d\n", popped->elem);
free(popped);
}
}
}
}
The struct I have implemented is this one:
struct cell {
int elem;
struct cell *next;
};
The problem, now, is that the function clears everything except for the last element which keeps stored into the heap.
What have I done that brings to this behaviour?

You have to pass the pointer to the top node by reference.
void printStack( struct cell **p){
struct cell *popped;
if ( *p == NULL ) {
printf("The stack is empty\n");
} else {
while ( *p != NULL ) {
popped = pop( p );
if(popped != NULL) {
printf("Value popped: %d\n", popped->elem);
free(popped);
}
}
}
}
And if the pointer to the top node has for example the name p then the function is called like
printStack( &p );
Otherwise the original pointer passed as an argument will not be changed because the function deals with a copy of its value.
So the effect of passing by value is that the data member next of the original pointer to the top node will be set to NULL due to this statement
temp->next = NULL;
within the function pop while the original pointer itself will store the same value that it had before calling the function printStack.
Take into account that you could rewrite the while loop within the function the following way
while ( ( popped = pop( p ) ) != NULL ) {
printf("Value popped: %d\n", popped->elem);
free(popped);
}

Related

Problem deleting the only node from a linked list

I am trying to create a function to delete a certain node if its value matches the value entered by the user. I created a case if there is only a single node, but after deleting the node with free(curr_node) and calling traverse function, the cmd prints out numbers endlessly. What am I missing?
typedef struct Node {
int data;
struct Node *next;
}Node;
Node *head = NULL;
int node_number = 0;
void traverse(Node *head, int count) {
int i = 1;
if(head == NULL) {
printf("No nodes to traverse!");
return;
}
printf("%d node(s), with their respective value: \n", count);
while(head != NULL) {
if(i == count)
printf("%d\n", head->data);
else
printf("%d-", head->data);
head = head->next;
i++;
}
}
void delete_item(Node *head) {
Node *curr_node = head;
int value;
printf("Enter value to search by: ");
scanf("%d", &value);
while(curr_node != NULL) {
if(curr_node->data == value) {
if(curr_node->next == NULL) {
free(curr_node);
head = NULL;
printf("Node deleted successfully!\n");
return;
}
}
//curr_node = curr_node->next;
}
}
Node *create_item() {
Node *result = NULL;
result = (Node *)malloc(sizeof(Node));
if(result == NULL) {
printf("Couldn't allocate memory!");
return 0;
}
printf("Value of node %d: ", node_number + 1);
scanf("%d", &result->data);
result->next = NULL;
node_number++;
return result;
}
int main() {
int nodes;
Node *temp;
head = create_item();
delete_item(head);
traverse(head, node_number);
return 0;
The change to head is not captured by the caller. The fact is, head is actually a local variable to delete_node, and any changes to it (not to be confused with changed through it using deference operations), are not being captured by the caller.
All function arguments in C are by-value. Some will say "that's not true for arrays"; they're wrong. Used in an expression, the "value" of an array is defined by the language standard as a temporary pointer referring to the address of the first element. I.e. still by-value, its just the value isn't what you may expect. But in your case, head is by value. If you had a function void foo(int x) you already know that modifying x within foo does not change the caller's int they passed; the same is true here. Just because its a pointer makes no difference. If you want to modify a caller-argument you have to build the road to get there.
There are two general schools around this.
Use a pointer to pointer argument and pass the address of head in main. This requires deference of the pointer-to-pointer to get the actual list head, but also allows you to modify the callers pointer.
Use the return result of the function to communicate the current list head back to the caller (i.e. the head after whatever operation is being performed.
The first is more complicated, but allows you to use the return result for other purposes (like error checking, hint). The latter is easier to implement. Both will accomplish what you want. The former is shown below:
void delete_item(Node **head)
{
int value;
printf("Enter value to search by: ");
if (scanf("%d", &value) == 1)
{
while (*head)
{
if ((*head)->data == value)
{
void *tmp = *head;
*head = (*head)->next;
free(tmp);
printf("Node deleted successfully!\n");
break;
}
head = &(*head)->next;
}
}
}
The caller, main in this case, needs to be modified as well:
delete_item(&head); // <== note passed by address now.

Deleting a linked list node in a C function doesn't transfer to the calling function

I have this C function which is supposed to find an element in the linked list which has a specific "pos" value, delete it, and return the deleted value to the calling function. It does delete the item, but the change isn't saved in the calling function, the list just doesn't get updated with the new changes.
My list is structured like this:
struct list{
int value;
int pos;
struct list * next_ptr;
};
And my C function is this:
bool findDeleteElement(struct list **ptr, int position, int *value){
struct list** temp = ptr;
if(*ptr!=NULL){
while((*ptr)->pos!=position) ptr=&(*ptr)->next_ptr; //Gets to desired node
temp=ptr;
value=&(*ptr)->value; //saves the value
temp=&(*temp)->next_ptr; //Goes to next node
ptr=temp; //Makes ptr point to next node
return 1;
}
else return 0;
}
I just can't see what I'm missing.
I'm a beginner so I probably made a simple mistake.
Change to:
*value = (*ptr)->value; //saves the value
You only set value, the local copy of your external variable's address. This does not change your external variable in the calling function.
Some question:
What happens when position has the wrong value, such that no node is found?
What's the purpose of temp = ptr;, because temp is overwritten by temp = &(*temp)->next_ptr; without having been used.
Disclaimer: I've not further checked this function.
I kindly advise you to take on other code formatting rules that add more air and make things more readable. Here's an example:
bool findDeleteElement(struct list **ptr, int position, int *value)
{
struct list** temp = ptr;
if (*ptr != NULL)
{
// Gets to desired node
while((*ptr)->pos != position)
{
ptr = &(*ptr)->next_ptr;
}
temp = ptr;
*value = (*ptr)->value; // Saves the value
temp = &(*temp)->next_ptr; // Goes to next node
ptr = temp; // Makes ptr point to next node
return 1;
}
else
{
return 0;
}
}
You are confused about pointers and dereferencing and what & and * actually do. This is a normal state of affairs for a beginner.
To start with, ptr and value when used without * preceding them are function arguments and like automatic (local) variables they disappear when the function scope exits. So this statement:
value=&(*ptr)->value;
Merely changes the value of value i.e. what it points to and has no visible effect to the caller. What you need to change is the thing that value points to. i.e. the statement should look like this:
*value = (*ptr)->value;
The difference is that instead of setting value to the address of (*ptr)->value it sets what valuepoints to to (*ptr)->value.
You have a similar problem with ptr. But your problems are more subtle there because you are also trying to use it as a loop variable. It's better to separate the two uses. I'd write the function something like this:
bool findDeleteElement(struct list **head, int position, int *value)
{
struct list* temp = *head;
struct list* prev = NULL;
while(temp != NULL && temp->pos != position)
{
prev = temp;
temp = temp->next;
}
if (temp == NULL) // position not found
{
return false;
}
else
{
*value = temp->value;
// Now need to delete the node.
if (prev != NULL)
{
// If prev has been set, we are not at the head
prev->next = temp->next; // Unlink the node from the list
}
else // We found the node at the head of the list
{
*head = temp->next;
}
free(temp); // Assumes the node was malloced.
return true;
}
}
The above is not tested or even compiled. I leave that as an exercise for you.
int delete(struct llist **pp, int pos, int *result)
{
struct llist *tmp;
while ( (tmp = *pp)) {
if (tmp->pos != pos) { pp = &tmp->next; continue; }
*result = val;
*pp = tmp->next;
free(tmp);
return 1;
}
return 0;
}

Global linked list pointing to NULL when passed through a function

I am facing this issue, in which if I am passing a linked list (which I defined as global) through a function (to insert a node), I am always getting a NULL value once the pointer returned to main function.
However, if I am adding the node to the global defined, it is working fine which is expected too. Can someone please help me why this piece of code didn't work and *list always points to NULL
struct node{
int val;
struct node *next;
};
typedef struct node node;
static node *list=NULL;
boolean add_node(node *list, int n, int val)
{
node *temp=NULL;
temp = (node *)malloc(sizeof(node));
temp->val = val;
temp->next = NULL;
if((list==NULL) && (n!=0))
{
printf("link list is NULL and addition at non zero index !");
return (FALSE);
}
if(list==NULL)
{
printf("list is NULL ");
list= temp;
}
else if(n==0)
{
temp-> next = list;
list=temp;
}
else
{
node *temp2;
temp2 = list;
int count =0;
while(count++ != (n-1))
{
temp2 = temp2->next;
if(temp2==NULL)
{
printf("nth index %d is more then the length of link list %d ",n,count);
return (FALSE);
}
}
node *temp3;
temp3 = temp2->next;
temp2-> next = temp;
temp->next = temp3;
}
printf("List after node insertion \n");
print_link_list(list);
return (TRUE);
}
main()
{
c= getchar();
switch(c)
{
case 'I':
{
printf("Insert a index and value \n");
int index,value;
scanf_s("%d",&index);
scanf_s("%d",&value);
if(add_node(list,index,value)==FALSE)
{
printf("Couldn't add the node \n");
}
if(list==NULL)
{
printf("\n After Insert op.,list is NULL, add %x",list);
}
else
{
printf("After Inset op., list is not Null, add %x",list);
}
}
break;
case 'D':
....
}
The global variable list is never modified, only the parameter list.
You probably want that parameter to be a pointer to a pointer, and assign through, instead of to, the parameter.
Try changing the function definition to use a pointer to a pointer:
boolean add_node(node **list, int n, int val)
You need to do this because your global variable list needs to be updated. The global is a pointer: an address. In your add_node function when you say list = temp you are only modifying the local pointer (also named list). When you leave the function the global list remains unchanged. However, if you pass a pointer to that global pointer (the pointer to a pointer) you are then able to modify the address stored in the original pointer.
An example:
int *pGlobal = NULL;
void someThing(int *pInt)
{
int LocalInt = 3;
pInt = &LocalInt; // I can change where this pointer is pointing - it's just a copy
// pGlobal remains unchanged
}
void someThingElse(int **ppInt)
{
// I am now modifying the ADDRESS of a pointer that we have the address of
*ppInt = malloc(sizeof(int));
// pGlobal has been changed to point at my allocated memory
}
void main()
{
// This passes a COPY of the address held in pGlobal
someThing(pGlobal);
// Here we are now passing a pointer (address) TO another pointer.
// The pointer pGlobal does occupy some real space in memory. We are passing a
// COPY of the value of its location so we can modify it.
someThingElse(&pGlobal);
}
Also, for good practice, don't name a global the same as a local variable (list) or parameter - it'll compile but can easily cause problems/confusion/bugs!

How to pass a struct by reference and change its value

Hello everyone I have this problem with my C code.
I'm implementing a stack and whenever I do pop it changes the stack in the function pop, but not the original stack .
please help.
here is my code
char pop(Node* top)
{
char result ;
if (size == 0) // The stack is empty.
{
return '\0' ;
}
else //The stack contains at least one element .
{
result = top->opp ;
top = top->next ;
}
size-- ;
return result;
}
We need more code but I will try:
I guess you use this function like this:
char pop(Node* top)
{
char result ;
if (size == 0) // The stack is empty.
{
return '\0' ;
}
else //The stack contains at least one element .
{
result = top->opp ;
top = top->next ;
}
size-- ;
return result;
}
int main()
{
// this is the top of the stack
Node *stack; // let's say there already are some elements in this stack
pop(stack);
return 0;
}
The problem is that you want to change the pointer value, then stack will point to the top of the stack. In order to do that, you have to use a pointer to a pointer, like this:
char pop(Node** top)
{
char result ;
Node *ptr;
ptr = *top;
if (size == 0) // The stack is empty.
{
return '\0' ;
}
else //The stack contains at least one element .
{
result = (*top)->opp ;
(*top) = (*top)->next ;
// You should free the pointer, like user2320537 said in his answer.
free(ptr);
}
size-- ;
return result;
}
int main()
{
// this is the top of the stack
Node *stack; // let's say there already are some elements in this stack
pop(&stack); // You give the pointer address
return 0;
}
Try char pop(Node** top) and operate on (*top)
You need to free the current position of top also... use free as
Node *ptr;
ptr = top;
if (size == 0) // The stack is empty.
{
return '\0' ;
}
else //The stack contains at least one element .
{
result = top->opp ;
top = top->next ;
}
free(ptr);
=================================================================
call it as
int main(){
Node front = NULL:
// place your code of PUSH here.
pop(&front); // will call the function **pop**
}
}
if you change the value of a variable you pass a pointer ( its address) to a function
eg
void increment(int *p) {
p += 1;
}
similarly to change the value of a POINTER you need to pass a pointer to the pointer to the function
char pop(Node **top) {
char t;
Node *p;
if( size == 0 ) {
return '\0';
} else {
p = *top;
t = p->op;
(*top) = (*top)-> next;
free(p);
return t;
}
}
Please send reference of top pointer to pop function like as "char pop(Node **top) { }" and add change your else block "top[0] = top[0]->next;" instead of "top = top->next ;".

Odd NULL pointer behavior

I'm attempting to implement a stack using a linked list. My stack constructor createStack() creates an empty (dummy) Element and returns a double pointer to that element (top of stack). My push() method checks if the stack has a dummy element; if it does it fills the dummy and returns, otherwise it allocates memory for a new element and does the necessary pointer updates.
The problem I have is that my *stack->next pointer apparently points to NULL (0x0) as it should, and then two lines later it doesn't equal NULL (0x17) but somehow passes the NULL test. Inside the call to push it equals (0x17) again but this time it fails the NULL test, as it should.
So my question is, what the heck is going on with this pointer? How/why did it change from (0x0) to (0x17), and if it equals (0x17) how did it pass the ==NULL test??
//main.c
int main () {
struct Element **stack;
stack = createStack();
printf("stack: %p\n", stack );
printf("*stack->next: %p\n", (*stack)->next );
if ( (*stack)->next == NULL )
printf("yes the pointer is null\n" );
printf("*stack->next: %p\n", (*stack)->next );
if ( (*stack)->next == NULL )
printf("yes the pointer is null\n" );
push ( stack, 1000 );
//stack.c
struct Element {
int value;
struct Element *next;
};
int push ( struct Element **stack, int el ) {
if ( (*stack)->next == NULL) {
// first element, fill dummy element and return
printf("first value: %i !", el);
(*stack)->value = el;
return 1;
}
printf("the pointer is not null\n");
struct Element *newElement = malloc( sizeof( struct Element ) );
if ( !newElement )
return -1;
newElement->value = el;
//add element to front of list
newElement->next = *stack;
//update pointer to new first element
*stack = newElement;
return 1;
}
struct Element** createStack() {
struct Element *dummy = malloc( sizeof( struct Element ) );
if (dummy == NULL )
printf("malloc failed...");
dummy->value = 99;
dummy->next = NULL;
struct Element **stack;
stack = &dummy;
return stack;
}
The code above produces the following output:
stack: 0x7fff6c385ba8
*stack->next: 0x0
yes the pointer is null
*stack->next: 0x17
yes the pointer is null
the pointer is not null
Forget for a moment that you're working with pointers and pointers-to-pointers, and suppose your createStack() routine looked like this:
int *createInt() {
int dummy = 1;
return &dummy;
}
The function allocates (temporary) space on the stack for the local variable dummy, assigns it a value, and then returns a pointer to it. This is exactly what your createStack() does, except that your dummy happens to be a more complicated data type.
The problem is that the memory allocated to dummy itself is released when the function returns and pops its local variables off the stack. So the function returns a pointer to memory that has become available for re-use. It then can (and does) change as data is pushed and popped from the stack during subsequent function calls.
The variable dummy within createStack() ceases to exist when that function returns - so the pointer that you return points at a variable which doesn't exist anymore.
This is why you see the odd behaviour - printf() is likely writing over the memory that formerly contained dummy, so when you try to examine that memory via your dangling pointer, you see it change unexpectedly.
You can fix the code by changing createStack() to return a struct Element * value:
struct Element *createStack(void)
{
struct Element *dummy = malloc( sizeof( struct Element ) );
if (dummy == NULL )
printf("malloc failed...");
else {
dummy->value = 99;
dummy->next = NULL;
}
return dummy;
}
and changing main() to suit (push() can remain unchanged):
int main ()
{
struct Element *stack;
stack = createStack();
printf("stack: %p\n", stack );
printf("stack->next: %p\n", stack->next );
if ( stack->next == NULL )
printf("yes the pointer is null\n" );
printf("stack->next: %p\n", stack->next );
if ( stack->next == NULL )
printf("yes the pointer is null\n" );
push ( &stack, 1000 );
In the createStack function you are returning the address of a local variable which leads to undefined behaviour:
struct Element** createStack() {
struct Element *dummy = malloc( sizeof( struct Element ) );
...
struct Element **stack;
stack = &dummy;
return stack;
}
Instead you can just have a pointer to struct Element in main and return the pointer to the newly created node from the createStack function:
struct Element *stack = createStack();
And pass the address of the pointer stack to the ush function:
push ( &stack, 1000 );

Resources