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 );
Related
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);
}
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;
}
}
stack.h
#define MAX_STACK 10
typedef int STACK_ITEM;
typedef struct Stack *STACK ;
stack.c
#include"stack.h"
struct Stack{
STACK_ITEM contents[MAX_STACK];
int tos;
};
_Bool create_stack(STACK s){
s = malloc(sizeof(struct Stack));
if(s == NULL )
return 0;
s->tos = 0;
return 1;
}
When calling the create_stack function, it doesn't affect s (pointer to structure) at all. So, my question is: why is s not changing, even though it is a pointer, not a value, passed?
Remember, all parameters are passed by value in C.
When you pass a pointer as a function parameter, you can access the object (or array of objects) pointed to by that pointer.
Your create_stack() is passed a pointer to a struct Stack, that is the s parameter. It then ignores the original value of s and reassigns it. That is allowed, but note that it does not change the original pointer in the caller of create_stack() because function parameters are passed by value.
There are two ways to do what you want.
The first way is to pass a pointer to a pointer:
_Bool create_stack(STACK *s){
*s = malloc(sizeof(struct Stack));
if(*s == NULL )
return 0;
(*s)->tos = 0;
return 1;
}
Call it e.g.:
STACK mystack;
_Bool ret;
ret = create_stack(&mystack);
if (!ret) {
/* error */
}
The second way is to not pass anything and return a pointer to the allocated stack:
STACK create_stack(void){
STACK s = malloc(sizeof(struct Stack));
if(s != NULL ) {
s->tos = 0;
}
return s;
}
Call it e.g.:
STACK s;
s = create_stack();
if (s == NULL) {
/* error */
}
Finally, as a point of programming style, do not typedef pointers in the way you have done. It is clearer if the pointer is explicit, for example, use typedef struct Stack STACK; instead of typedef struct Stack *STACK; and adjust the usage accordingly, for example, replacing STACK s with STACK *s and replacing STACK *s with STACK **s.
Function parameters are its local variables. That is the parameters hold copies of the passed arguments. To change an original argument in a function you have to pass it by reference through pointer.
So change the function like
_Bool create_stack(STACK *s){
*s = malloc(sizeof(struct Stack));
if(*s == NULL )
return 0;
( *s )->tos = 0;
return 1;
}
In order for a C function to modify an argument, the argument must be given as a pointer to the value to be changed. Thus, for a simple integer argument:
void Inc(int *value) {
++(*value);
}
will do the trick, but:
void Inc(int value) {
++value;
}
will do absolutely nothing to any argument given in a call to Inc, as the function just gets a copy of the 'value' given.
The same goes for a pointer! Your function just changes a copy of the pointer it is passed. So, you should change your function to take a pointer to the pointer:
_Bool create_stack(STACK *s){ // Pointer to a pointer to Stack
*s = malloc(sizeof(struct Stack)); // Change the value of the STACK object pointed to
if (*s == NULL )
return 0;
(*s)->tos = 0; // And, again, we need to (singly) dereference to 'double' pointer
return 1;
}
Then, in your calling code, where you originally have something like:
_Bool answer = create_stack(myStackPointer);
you would need to add the address of your pointer:
_Bool answer = create_stack(&myStackPointer);
Feel free to ask for further clarification and/or explanation.
I have a small program got from this link which pushes element into the stack.On careful examination I see that the storage space taken by this next pointer in the program for the first value ,second value,and third value is different.Can anyone please give me a satisfactory explanation for why it is happening like this.
I am using gcc compiler
#include <stdlib.h>
#include <stdio.h>
struct Node
{
int data;
struct Node *next;
};
int push_front( struct Node **head, int data )
{
struct Node *tmp = malloc( sizeof( struct Node ) );
int success = tmp != NULL;
if ( success )
{
tmp->data = data;
tmp->next = *head;
*head = tmp;
printf("\nAddress of pointer head now is %p for value %d",*head,data);
}
return success;
}
int main( void )
{
struct Node *head;
for ( int i = 0; i != 10; i++ ) push_front( &head, i );
return 0;
}
=======================================================================
output
-----
Address of pointer head now is 0x16f1010 for value 0
Address of pointer head now is 0x16f1440 for value 1
Address of pointer head now is 0x16f1460 for value 2
Address of pointer head now is 0x16f1480 for value 3
Address of pointer head now is 0x16f14a0 for value 4
Address of pointer head now is 0x16f14c0 for value 5
Address of pointer head now is 0x16f14e0 for value 6
Address of pointer head now is 0x16f1500 for value 7
Address of pointer head now is 0x16f1520 for value 8
Address of pointer head now is 0x16f1540 for value 9
The expectation is such that the header pointer should take equal bytes of address space while inserting each value.
malloc is used to dynamically allocate a contiguous block of memory of a given size. This memory is allocated from the heap.
malloc makes no guarantees that the memory allocated between two subsequent calls to malloc be contiguous.
I'm doing an exercise, and want support about it. The problem is this: I have two structures (1 for the nodes of the stack, 1 for the stack). In the node structure, there is a void* data field.
I've tried to push a value on the stack but, because of void* data instead of simple data, I failed.
This is the code about the structures and the push() function.
struct upo_stack_node_s
{
void *data;
struct upo_stack_node_s *next;
};
typedef struct upo_stack_node_s upo_stack_node_t;
struct upo_stack_s
{
upo_stack_node_t *top;
size_t size;
};
/*Function for create the stack*/
upo_stack_t upo_stack_create()
{
upo_stack_t stack = malloc(sizeof(struct upo_stack_s));
if (stack == NULL)
{
fprintf(stderr, "Unable to create a stack!\n");
abort();
}
stack->top = NULL;
stack->size = 0;
return stack;
}
/*Push() function:*/
void upo_stack_push(upo_stack_t stack, void *data)
{
/* TO STUDENTS:
* Remove the following two lines and put here your implementation
*/
upo_stack_node_t *node = malloc(sizeof(struct upo_stack_node_s));
node->data = data; /*<-- Here's the problem */
node->next = stack->top;
stack->top = node;
++stack->size;
}
/*Top() function*/
void* upo_stack_top(const upo_stack_t stack)
{
/* TO STUDENTS:
* Remove the following two lines and put here your implementation
*/
return (void *)(stack->top); //<---
}
/*Function for testing (there are other functions in the code)*/
void test_top()
{
int value1 = 1;
int value2 = 2;
upo_stack_t stack;
stack = upo_stack_create();
upo_stack_push(stack, &value1); //<----
upo_stack_push(stack, &value2); //<----
assert( upo_stack_top(stack) != NULL );
assert( *((int*) upo_stack_top(stack)) == value2 ); <-- Here's the error
upo_stack_pop(stack, 0);
assert( upo_stack_top(stack) != NULL );
assert( *((int*) upo_stack_top(stack)) == value1 );
upo_stack_pop(stack, 0);
assert( upo_stack_top(stack) == NULL );
upo_stack_destroy(stack, 0);
}
You always have to pass a void pointer. That means if you want to pass a simple value, like 1, what you need to do is, is to allocate an integer value, and pass the pointer to it (as a void pointer).
Thus something like:
int x = 4;
upo_stack_push(upo_stack, &x);
Of course you have to make sure the int variable x does not go out of scope, otherwise the pointer will point to freed memory, which results in nasty memory problems.
Update
It is assumed above, that the void pointer you pass is stored already in memory for the scope of the stack. In case, you want the stack itself to copy the data, you have also to malloc space for that, thus not only mallocing the node, but also mallocing and copy the data type passed. Also to know the size of the data (since it is a void pointer, which is unaware of its type), you have to add an int size parameter to the push function.
For an integer value to be stored, pass it as a pointer, with size: sizeof(int). Than for copying the data structure, use memcpy. This only works for simple types and structures without pointers. If you have to copy structures with pointers (thus you need so called deep-copying), than it is more tricky.