The partial code, in C, is here:
typedef struct List {
double v;
struct List *next;
} List;
void deleteList (List **p) {
*p = (*p)->next;
}
I am confused about how the deleteList function is working. So the arguement is a pointer to a pointer to a List structure. So we have:
p : pointer_2 --> pointer_1 --> List
So I have some questions:
So what is *p in the function deleteList()? Is it pointer_1 or something else?
Does *p before = mean the same as *p after the = sign?
Is there a difference between *p and (*p) ?
Say we have:
... la --> lb --> lc --> ld ....
And say we want to delete lb. I get the idea, theoretically. You alter the la->next to point to lc. But I am confused about the pointer business.
What is the argument to deleteList()?
Is it, deleteList(la->next)? Or something else?
And then the really confusing part.
*p = ... is supposed to be la->next because this is the pointer we want to alter.
But then ...(*p)->next, wouldn't this just be the lb? But we want lc? So it seems like
*p have different meaning in the same line?!
Let;s at first write the function correctly.
void deleteList( List **head )
{
while ( *head != NULL )
{
List *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
}
A pointer to the head node is passed to the function by reference.
If you will define the function like
void deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
}
that is if the pointer will not be passed by reference then the function will deal with a copy of the pointer. Changing a copy does not influence on the original pointer.
Consider the following demonstrative program.
#include <stdio.h>
#include <stdlib.h>
void f( int *p )
{
p = NULL;
}
int main(void)
{
int x = 10;
int *px = &x;
printf( "Before the function call px = %p\n", ( void * )px );
f( px );
printf( "Adter the function call px = %p\n", ( void * )px );
return 0;
}
Its output might look like
Before the function call px = 0x7ffe26689a2c
Adter the function call px = 0x7ffe26689a2c
That is the original pointer px was not changed because the function dealt with a copy of the pointer.
To change the pointer you need to pass it to the function by reference
#include <stdio.h>
#include <stdlib.h>
void f( int **p )
{
*p = NULL;
}
int main(void)
{
int x = 10;
int *px = &x;
printf( "Before the function call px = %p\n", ( void * )px );
f( &px );
printf( "Adter the function call px = %p\n", ( void * )px );
return 0;
}
Now the program output might look like
Before the function call px = 0x7ffed60815fc
Adter the function call px = (nil)
Within the function you need to dereference the parameter to get the access to the passed by reference pointer.
*p = NULL;
^^^^
The same occurs in the function deleteNode. To check whether the passed pointer is equal to NULL there is used the following statement
while ( *head != NULL )
^^^
To access the data member next of the node pointed to by the origibal pointer you again have to dereference the parameter to get access to the original pointer
*head
So this expression yields the original pointer. So to access the data member next you have to write
( *head )->next
You are using the parentheses because the postfix operator -> has a higher priority but you need at first to get the original pointer.
That is if you had no a referenced pointer you would write
head->next
But when you have a referenced pointer that is when you have a pointer to an original pointer then to get the original pointer you have to derefernce the referenceing pointer like
( *head )->next
You could write the function without accepting the pointer to the head node by reference. But in this case you should to add in the caller one more statement that will set the pointer head to NULL.
For example
void deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
}
and in the caller you need to write
List *head - NULL;
// the code thatf fills the list
deleteList( head );
head = NULL;
Or the function could return a null pointer like
List * deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
return head;
}
and in the caller you could write
List *head - NULL;
// the code thatf fills the list
head = deleteList( head );
The advantage of defining the function that accepts the pointer to the head node by reference is that the user of the function does not need to remember to set the pointer to NULL by himself.
in deleteList function: before you pass to the next element you must free the element you point to.
void deleteList (List **p) {
while(*p != NULL){
List *nextNode = (*p)->next;
free(*P);
*p= nextNode;
}
}
Related
I need to know how to modify the free function to remove the first element of the list (last added). I must not interfere with the main function.
This is how the last element added to me remains in the list.
typedef struct TEmployee
{
struct TEmployee *m_Next;
struct TEmployee *m_Bak;
char *m_Name;
} TEMPLOYEE;
TEMPLOYEE *newEmployee (const char *name, TEMPLOYEE *next)
{
TEMPLOYEE *n = (TEMPLOYEE*) malloc(sizeof(*next));
n->m_Name = (char*) malloc(sizeof(char)*100);
strcpy(n->m_Name, name);
n->m_Bak = NULL;
n->m_Next = next;
return n;
}
void freeList ( TEMPLOYEE *q )
{
TEMPLOYEE *x = q;
while( x != NULL)
{
TEMPLOYEE *tmp = x->m_Next;
free(x);
x = tmp;
}
free(x);
x=NULL;
}
Currently, the freeList method deletes all the elements in the linked list.
To just delete the first element of a linked list, the algorithm should be as follows:
Given the head as the input.
It could be possible that the head itself is NULL meaning the list is already empty, in that case we can simply return.
In the other case, we can simply set head = head->m_Next.
Now, since we also have previous pointers, we need to update the previous pointer for the current head, i.e. head->m_Back = NULL.
Please try to use the above algorithm and write the updated freeList method.
The problem is that you pass the pointer to the first element by value. If you want to modify the value of the head pointer, you need to pass it by reference, as in:
void freeList ( TEMPLOYEE **q )
{
TEMPLOYEE *x = *q;
while( x != NULL)
{
TEMPLOYEE *tmp = x->m_Next;
free(x);
x = tmp;
}
/* free(x); this is incorrect, tmp is already NULL when you
* get out of the while loop
* x=NULL; // and this is nonsense, it's already NULL and you are not
* // using x anymore.
*/
*q = NULL; /* this is what you lack, to assign NULL to the pointer. */
}
Later, you need to call freelist() as follows:
freelist(&list_head);
to pass a reference of the pointer instead of the pointer's value.
It cannot reliably be done without modifying the caller.
In it's basic form, you just have to free the node and trust that nobody uses it anymore:
void freeFirst ( TEMPLOYEE *q )
{
if (q) {
free(q->m_Name);
free(q);
}
}
Now to make this a bit more reliable, you should also modify the queue head node. This can be done by passing a double pointer to allow modification of the head node pointer:
void freeFirst ( TEMPLOYEE **q )
{
TEMPLOYEE *x = *q;
if (*q) {
*q = (*q)->m_Next;
free(*x->m_Name);
free(*x);
}
}
Now it's important that the caller is modified, instead of freeList(list) you would now need freeList(&list).
Not that I have also freed the m_Name member, because otherwise you will leak the memory.
You should also use strdup instead of your combination of malloc of arbitrary length and strcpy, that could cause a buffer overflow.
I'm currently learning C and also some datastructures such as binary search trees etc. I have trouble understanding HOW exactly changing pointer values within a function works in some cases and in others doesn't... I'll attach some of my code I wrote. It's an insert function which inserts values in the correct places in the BST (it works as it should). I tried working with pointers to pointers to be able to change values withing a function. Even though it works, im still really confused why it actually does.
I don't quite understand why my insert function actually changes the BST even though I only work with local variables (tmp, parent_ptr) in my insert function and I don't really dereference any pointers apart from " tmp = *p2r " in the insert function.
Thanks for helping out.
#include <stdio.h>
#include <stdlib.h>
struct TreeNode{
int val;
struct TreeNode *left;
struct TreeNode *right;
};
struct TreeNode** createTree(){
struct TreeNode** p2r;
p2r = malloc(sizeof(struct TreeNode*));
*p2r = NULL;
return p2r;
}
void insert(struct TreeNode** p2r, int val){
// create TreeNode which we will insert
struct TreeNode* new_node = malloc(sizeof(struct TreeNode));
new_node -> val = val;
new_node -> left = NULL;
new_node -> right = NULL;
//define onestep delayed pointer
struct TreeNode* parent_ptr = NULL;
struct TreeNode* tmp = NULL;
tmp = *p2r;
// find right place to insert node
while (tmp != NULL){
parent_ptr = tmp;
if (tmp -> val < val) tmp = tmp->right;
else tmp = tmp->left;
}
if (parent_ptr == NULL){
*p2r = new_node;
}
else if (parent_ptr->val < val){ //then insert on the right
parent_ptr -> right = new_node;
}else{
parent_ptr -> left = new_node;
}
}
int main(){
struct TreeNode **p2r = createTree();
insert(p2r, 4);
insert(p2r, 2);
insert(p2r, 3);
return 0;
}
Let's analyze the approach step by step.
At first we consider the following simple program.
#include <stdio.h>
#include <stdlib.h>
struct TreeNode{
int val;
struct TreeNode *left;
struct TreeNode *right;
};
void create( struct TreeNode *head, int val )
{
head = malloc( sizeof( struct TreeNode ) );
head->val = val;
head->left = NULL;
head->right = NULL;
}
int main(void)
{
struct TreeNode *head = NULL;
printf( "Before calling the function create head == NULL is %s\n",
head == NULL ? "true" : "false" );
create( head, 10 );
printf( "After calling the function create head == NULL is %s\n",
head == NULL ? "true" : "false" );
return 0;
}
The program output is
Before calling the function create head == NULL is true
After calling the function create head == NULL is true
As you can see the pointer head in main was not changed. The reason is that the function deals with a copy of the value of the original pointer head. So changing the copy does not influence on the original pointer.
If you rename the function parameter to head_parm (to distinguish the original pointer named head and the function parameter) then you can imagine the function definition and its call the following way
create( head, 10 );
//...
void create( /*struct TreeNode *head_parm, int val */ )
{
struct TreNode *head_parm = head;
int val = 10;
head_parm = malloc( sizeof( struct TreeNode ) );
//...
That is within the function there is created a local variable head_parm that is initialized by the value of the argument head and this function local variable head_parm is changed within the function.
It means that function arguments are passed by value.
To change the original pointer head declared in main you need to pass it by reference.
In C the mechanism of passing by reference is implemented by passing an object indirectly through a pointer to it. Thus dereferencing the pointer in a function you will get a direct access to the original object.
So let's rewrite the above program the following way.
#include <stdio.h>
#include <stdlib.h>
struct TreeNode{
int val;
struct TreeNode *left;
struct TreeNode *right;
};
void create( struct TreeNode **head, int val )
{
*head = malloc( sizeof( struct TreeNode ) );
( *head )->val = val;
( *head )->left = NULL;
( *head )->right = NULL;
}
int main(void)
{
struct TreeNode *head = NULL;
printf( "Before calling the function create head == NULL is %s\n",
head == NULL ? "true" : "false" );
create( &head, 10 );
printf( "After calling the function create head == NULL is %s\n",
head == NULL ? "true" : "false" );
return 0;
}
Now the program output is
Before calling the function create head == NULL is true
After calling the function create head == NULL is false
In your program in the question you did not declare the pointer to the head node like in the program above
struct TreeNode *head = NULL;
You allocated this pointer dynamically. In fact what you are doing in your program is the following
#include <stdio.h>
#include <stdlib.h>
struct TreeNode{
int val;
struct TreeNode *left;
struct TreeNode *right;
};
void create( struct TreeNode **head, int val )
{
*head = malloc( sizeof( struct TreeNode ) );
( *head )->val = val;
( *head )->left = NULL;
( *head )->right = NULL;
}
int main(void)
{
struct TreeNode **p2r = malloc( sizeof( struct TreeNode * ) );
*p2r = NULL;
printf( "Before calling the function create *p2r == NULL is %s\n",
*p2r == NULL ? "true" : "false" );
create( p2r, 10 );
printf( "After calling the function create *p2r == NULL is %s\n",
*p2r == NULL ? "true" : "false" );
return 0;
}
The program output is
Before calling the function create *p2r == NULL is true
After calling the function create *p2r == NULL is false
That is compared with the previous program when you used the expression &head of the type struct TreeNode ** to call the function create you are now introduced an intermediate variable p2r which stores the value of the expression &head due to this code snippet
struct TreeNode **p2r = malloc( sizeof( struct TreeNode * ) );
*p2r = NULL;
That is early you called the function create like
create( &head, 10 );
Now in fact you are calling the function like
struct TreeNode **p2r = &head; // where head was allocated dynamically
create( p2r, 10 );
The same takes place in your program. That is within the function insert dereferencing the pointer p2r you have a direct access to the pointer to the head node
if (parent_ptr == NULL){
*p2r = new_node;
^^^^
}
As a result the function changes the pointer to the head node passed by reference through the pointer p2r.
The data members left and right of other nodes are also changed through references to them using the pointer parent_ptr
else if (parent_ptr->val < val){ //then insert on the right
parent_ptr -> right = new_node;
^^^^^^^^^^^^^^^^^^^
}else{
parent_ptr -> left = new_node;
^^^^^^^^^^^^^^^^^^
}
While the pointers themselves are indeed local variables, they point to a specific location in memory. When you dereference the pointer by using the -> symbol, you're basically accessing the memory where that exact variable to which the pointer is pointing to is stored. This is why your changes are reflected outside the function as well.
You basically told a local variable where your tree is stored, it helped with the insertion, and then it went out of scope. The tree itself is not a local variable so the changes are reflected on it.
I suggest reading up on how pointers work.
First of all, always remember one thing about the pointers, they store a memory address, rather than a value. For example:
int val = 5;
int copy = val;
int *original = &val;
printf("%d\n", val);
printf("%d\n", copy);
printf("%d\n", *original);
val = 8;
printf("%d\n", val);
printf("%d\n", copy);
printf("%d\n", *original);
On executing this piece of code, the output will be
5
5
5
8
5
8
Notice, how on changing the value of val, the value of copy remains the same, and the value pointed the by original changes. This happens because the pointer original points to the memory location val.
Now, coming to the insert function, although you are only working with local variables(tmp, parent_ptr), but remember they are pointer variables, they refer to a memory address. So whenever within the loop, you traverse to tmp -> right or tmp -> left, you are actually jumping in memory from one location to another, in the correct order, that's why it works. The following example will make it more clear.
56 (A)
/ \
/ \
45 (B) 60 (C)
Consider the above BST, with the memory address in brackets. Let's insert 40 into this BST. Initially, tmp will point to A, address of 56. Now 40 is less than 56, so tmp goes to left and now points to B, address of 45. Once, again it goes to left and now it is null. But by now, parent_ptr points to B. So the new node for 40 gets attached to left of B.
56 (A)
/ \
/ \
45 (B) 60 (C)
/
/
40 (D)
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);
}
Generally, I know that a pointer stores the memory address of another value located in computer memory, for example:
int firstvalue= 5
int * p1;
p1 = &firstvalue; // p1 = address of firstvalue
What happens if we define an operation like the following in a linked list? Does *current=*list means that the value pointed to by current equals to the value pointed to by list? And what does it mean if we define ecur=current?
int function(struct list_t **list){
struct list_t *ecur=NULL;
struct list_t *current=*list;
ecur=current;
}
Update:
What does it do *list=remove(*list, param1, param2)? And why is that?
remove is a function that returns a modified list of list.
Update 2:
Why do we need to define a pointer to pointer in order to modify the list? Is *list a pointer to pointer?
The variable list is a pointer to a pointer to a struct list_t. If we (just as an example) assume that the struct is placed at address 2000 and that the unnamed pointer is at address 1000 it will look like this:
Then you have the initialization that adds two new variables. Both as pointer to a struct list_t.
struct list_t *ecur=NULL;
struct list_t *current=*list;
So the picture now becomes:
Notice that current got the same value as the "some-pointer" in the middle because it is *list that was assigned to current.
Then you have the assignment:
ecur=current;
which means that ecur gets the same value as current and gives the picture:
Update: What does it do *list=remove(*list, param1, param2) ?
It changes the value of the "some-pointer" in the middle of the picture. This is for instance needed if the remove function removes the first element in a linked list.
Why do we need to define a pointer to pointer in order to modify the list? Is *list a pointer to pointer?
Remember that C passes all function arguments by value - the formal argument in the function definition is a different object in memory from the actual argument in the function call. For example:
void swap( int a, int b )
{
int tmp = a;
a = b;
b = tmp;
}
void foo( void )
{
int x = 1;
int y = 2;
swap( x, y );
}
a is a different object in memory than x, and b is a different object in memory than y, so swapping a and b has no effect on x and y. In order to swap the values of x and y, you must pass pointers to them:
void swap( int *a, int *b )
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void foo( void )
{
int x = 1;
int y = 2;
swap( &x, &y );
}
The expression *a is the same as x, so writing to *a is the same as writing to x. Same for *b and y.
So, in order for a function to write to a parameter, you must pass a pointer to that parameter:
void foo ( T *arg )
{
*arg = new_value(); // writes a new value to the thing arg points to
}
void bar( void )
{
T var;
foo( &var ); // write a new value to var
}
This is true for any non-array type T. Let's replace T with a pointer type P *:
void foo( P **arg )
{
*arg = new_value(); // write a new *pointer* value to the thing arg points to
}
void bar( void )
{
P *var;
foo( &var ); // write a new pointer value to var
}
The semantics are exactly the same - all that's changed is the type.
If a function has the potential to modify a list * object (say pointing it at a new list head), then you must pass a pointer to that list * object:
void add_node( struct list_t **list, struct list_t *node )
{
if ( !*list || (node->value < (*list)->value) ) // make node new head of list
*list = node;
else
// add node somewhere else in the list
}
int main( void )
{
struct list_t *list = NULL;
...
struct list_t *node = newNode( value );
add_node( &list, node );
...
}
TYPE *p = ptype /*variable of type: TYPE * */;
is not an assignment. It's an initialization, which for an auto-matic (=on-the-stack) p can be rewritten as:
TYPE *p;
p = ptype;
(not TYPE *p; *p=ptype; /*would be a type error*/)
In terms of your example:
struct list_t *current=*list;
sets where current will point to (the same place as what *list points to (*list is also a pointer because list is a doubly-indirect pointer)) without doing anything whatsoever with what current will point at (*current) after the initialization.
All of this is just conceptual, though. Your function doesn't have any externally visible effects so an optimizing compiler should completely delete its body.
I had a similar knot in my head with this post. I'd like to rearrange your function a bit, so it's easier to understand what's going on:
int function(struct list_t **list)
{
struct list_t *current = *list;
struct list_t *ecur = current;
}
If we call this function with an element foo we essentially get this:
struct list_t foo = { .data = "foo" };
struct list_t *bar = &foo;
struct list_t **list = &bar;
struct list_t *current = *list;
struct list_t *ecur = current;
We have five declarations and five assignments. For better readability, I'll write everything down without declarations:
foo = { .data = "foo" };
bar = &foo;
list = &bar;
current = *list;
ecur = current;
Now, let's walk through it:
foo is a struct. It contains the above data-field.
bar is a pointer to struct. It contains the address of foo
list is a pointer to a pointer to struct. It contains the address of bar
current is a pointer to struct. It contains the contents of the contents of list, which is the address of foo
ecur is a pointer to struct. It's identical to current and contains the address bar
In the end we can simplify the whole example to this:
struct list_t foo = { .data = "foo" };
struct list_t *ecur = &foo;
What does it all mean?
list: Because list is a pointer to a pointer you are able to modify bar to point to something completely different, by de-referencing it (*list = ...)
current/ecur: that's what bar originally pointed too. By de-referencing you could change the data-field itself ((*ecur).data = "banana" or better ecur->data)
I hope I could clarify things and didn't make it worse ;)
Why do we need to define a pointer to pointer in order to modify the
list?
Let me add a complete program, albeit short, to illustrate it better. It defines a simply linked list and builds it while keeping it ordered. Yes, I know it would be easier to simply call qsort(), but I want to demonstrate how adding one level of indirection —the pointer to pointer— allows to insert elements smoothly, without testing for special cases.
// C pointer exercise: sort arguments
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
struct list
{
char *arg;
struct list *next;
};
int main(int argc, char *argv[])
{
// pointer to base, running pointer and pointer to pointer
struct list *base = NULL, *p, **pp;
for (int i = 1; i < argc; ++i)
{
struct list *new_entry = malloc(sizeof(struct list));
if (new_entry)
{
new_entry->arg = argv[i];
// find where to insert new entry
for (pp = &base; *pp; pp = &(*pp)->next)
if (strcasecmp(new_entry->arg, (*pp)->arg) < 0)
break;
// insertion in a simply linked list
new_entry->next = *pp;
*pp = new_entry;
}
}
// display and cleanup
for (p = base; p;)
{
struct list * tmp = p->next;
puts(p->arg);
free(p);
p = tmp;
}
return 0;
}
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 );