Pointer not taking new value - c

For the following function:
/*this function removes the topmost item in the stack*/
void pop(Stack * S, NODE * returnNode) {
stackNode * temp;
if(S->root == NULL) {
ERROR("Sorry, cannot pop an empty stack!!\n");
}
else {
temp = S->root;
returnNode = temp->Item;/*x now points to the topmost node*/
S->root = temp->nextItem;/*stack points to the rest of the list*/
free(temp);/*returning memory to the system*/
}
}
I am expecting returnNode pointer to have the same value as the temp->Item, but when I am inspecting the value in GDB it doesn't. Am I missing something?
I should add that the temp value is being correctly set.

If you want to update a pointer as a parameter, you need to pass it's address. Otherwise, you are just updating the value on the call stack, which is local in scope.
void pop(Stack * S, NODE ** returnNode) {
stackNode * temp;
if(S->root == NULL) {
ERROR("Sorry, cannot pop an empty stack!!\n");
}
else {
temp = S->root;
*returnNode = temp->Item;/*x now points to the topmost node*/
S->root = temp->nextItem;/*stack points to the rest of the list*/
free(temp);/*returning memory to the system*/
}
}

Think of it this way,
in a function you can only modify the variable the pointer is pointing to, not the value, i.e. an address, of the pointer itself. If you want to modify the value of a pointer, you need to pass a pointer that points to it.
for example
if you have:
int k = 5, f = 15, *pk = &k, *pf = &f;
and you want to switch the values of pk and pf, you would need a function like this:
void change (int **m, int **n) {
int *help = *m;
*m = *n;
*n = help;
}
change(&pk, &pf);
printf("pk ist %i, pf ist %i\n", *pk, *pf);
/* pk ist 15, pf ist 5;*/

you should have *returnNode = temp->Item; instead of returnNode = temp->Item;.

Related

free() function does not clear well my stack

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);
}

Change passed pointer in function

Concerning double indirection (pointer to pointer) and passing those to a function
I cannot change the pointer here in function void test(int **nmbr, int *n);
int n = 5;
int n2 = 555;
int *nPtr = &n;
int *n2Ptr = &n2;
printf("the number = %d\n", *nPtr);
test(&nPtr, n2Ptr);
printf("the number is now = %d\n", *nPtr);
test
void test(int **nPptr, int *n2Ptr) {
int *p = *nPptr;
p = n2Ptr;
}
since the pointer p points to a copy of *nPtr, right?
But what about this code (this time the pointer points to a given struct in a linkedlist
the code snipped is from the site https://www.learn-c.org/en/Linked_lists
int remove_by_index(Person **head, int n) {
int i = 0;
int retval = -1;
Person *current = *head;
Person *temp_node = NULL;
if (n == 0) {
return pop_first(head);
}
for (i = 0; i < n-1; i++) {
if (current->next == NULL) {
return -1;
}
current = current->next;
}
temp_node = current->next;
retval = temp_node->nmbr;
current->next = temp_node->next;
free(temp_node);
return retval;
}
it removes a given node in the list by a given indexnumber
Here one can see that *current is local copy in the function and traversate in the list and lastly merges two nodes, without problem
So why does it work to change the pointer here but not in the function test(int **nPptr, int *n2Ptr)?
To be clear
in the function test:
int *p = *nPptr;
p is local copy and copies the pointer from *nPtr
in the function remove_by_index
Person *current = *head;
current is local copy and copies the pointer from *head. The list lives beyond the scope of the function remove_by_index(..) so I do not understand why it can be manipulated in the function by the local pointer *current, at the same time as it does not work to alter nPtr in function test(..)
In a function, changes to pointer variables or pointer parameters have no effect outside the function. However, if the pointer is pointing to an object outside the function, that object can be modified by dereferencing the pointer.
For example, in OP's test function:
void test(int **nPptr, int *n2Ptr) {
int *p = *nPptr;
p = n2Ptr;
}
p is initialized and then its value is changed by an assignment. This has no effect on any object outside the function. If the function were changed as follows:
void test(int **nPptr, int *n2Ptr) {
int *p = *nPptr;
p = n2Ptr;
*nPptr = p;
*p = 42;
}
Then two objects outside the function will have been modified (an int * and an int).
In OP's remove_by_index function, changes to the current variable as it progresses through the linked list have no external effect, but the line:
current->next = temp_node->next;
is equivalent to:
(*current).next = (*temp_node).next;
The external Person object that current is pointing to on the linked list has been modified by dereferencing of the pointer and assignment to the next member of the Person it is pointing to.

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;
}

How is the pointer (tree) returning 2 different values in 2 different lines?

I have the following code in my program:
/*Making a tree using linked lists.
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef struct node
{
int value;
struct node * left;
struct node * right;
}Node;
Node * tree;
Node * maketree(int number)
{
Node p = { number, NULL, NULL };
return &p;
}
int main()
{
int a[5] = { 1, 2, 3, 1, 4 };
int number;
number = a[0];
tree = maketree(number);
printf("Root has a value of %d\n", tree->value);
printf("Root has a value of %d\n", tree->value);
}
Output:
Root has a value of 1
Root has a value of "Some garbage value!"
I can't understand how tree points to some other address (or printing some garbage value somehow) when I'm not at all playing with it and printing its value in 2 successive lines!
You are returning &p, the address of a local variable.
This variable goes out of scope as maketree() exits, making it undefined behavior to dereference the pointer.
In practice you're dereferencing a pointer to stack space that was allocated by maketree(), but has been de-allocated and very likely re-used (by printf(), which is quite a heavy function) since. This is totally invalid code.
The fix is to allocate the new node on the heap:
Node * maketree(int number)
{
Node *p = malloc(sizeof *p);
if(p != NULL)
{
p->value = number;
p->left = p->right = NULL;
}
return p;
}
In the function
Node * maketree(int number)
{
Node p = { number, NULL, NULL };
return &p;
}
You are returning the adress of a local variable namely p. Being local means that the memory location of the variable p is no more reserved for p after the end of the function. Nothing prevent it to be overwriten. This is called an undefined behavior.
You should use a dynamic allocation:
Node * maketree(int number)
{
Node *pp;
pp = malloc(sizeof(*pp));
if(pp != NULL)
{
pp->value = number;
pp->left = NULL;
pp->right = NULL;
}
return pp;
}

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!

Resources