Home > OS >  Returning void** value of pop function in stack data-structure implementation
Returning void** value of pop function in stack data-structure implementation

Time:01-03

my exercise state as follow:

stack stack_push(stack s);
stack stack_pop(stack s, void **d);
//The second parameter of stack_pop function is requested in order to pass back to the caller the data fetched from the stack.

I'm having troubles when returning the value of the element removed after the pop function: I can't pass back the value of the removed element, because the pop function already returns the stack itself; therefore, I should pass back the value using the void **d variable.

But I'm obtaining segmentation fault error when trying to read the i variable in the STACK.C file. (The stack was supposed to deal with different data types, that is why I used a container struct, in order to store an int for the data type (eg. 1 for int, 2 for float, etc.), and the effective value in the void* value variable.

STACK.H

typedef struct _stack stack;
typedef struct _node node;
typedef struct _container container;

struct _node{
   void *data;
   struct _node *below;
};

struct _stack{
   node *base;
   node *top;
};

struct _container{
   int i;
   void *value;
};
#define STACK_EMPTY {NULL,NULL}

STACK.C

int main(){
   
   stack my_stack = STACK_EMPTY;
   
   ...

      switch(chose){
         case 1:
            my_stack = stack_push(my_stack);
            break;
         case 2:
            void **d = NULL; //d will contains the returned value.
            my_stack = stack_pop(my_stack, d);     
            container *cont = (container*)*d; 
            printf("%d", cont->i); //SEGMENTATION FAULT ERROR HERE
            break;
         case 3:
            stack_print(my_stack);
            break;
         default:
            break;
      }      
   }
}

STACK_OPERATIONS.H

#define MAX_STRING_SIZE 15

stack stack_push(stack s){
   ...
   int *push_int = malloc(sizeof(int));
   float *push_float = malloc(sizeof(float));;
   char *push_char = malloc(sizeof(char));;
   char *push_char_arr = malloc(sizeof(char)*MAX_STRING_SIZE 1);

   node *my_node = malloc(sizeof(struct _node));
   container *my_container = malloc(sizeof(struct _container));

   my_node->data = my_container;

   switch(chose_push){
      case 1:
         ...
         my_container->i = 1;
         my_container->value = push_int; 
      case 2:
         ...
         my_container->i = 2;
         my_container->value = push_float;
      case 3:
         ...
         my_container->i = 3;
         my_container->value = push_char;
      case 4:
         ...
         my_container->i = 4;
         my_container->value = push_char_arr;     
   }

   if(s.base == NULL && s.top == NULL){
      //Stack is empty
      my_node->below = NULL;
      s.base = my_node;
      s.top = my_node;
   } else {
      my_node->below = s.top;
      s.top = my_node;
   }
   return s;
}

stack stack_pop(stack s, void **d){
   if(s.base == NULL && s.top == NULL){
      //Stack is empty
      puts("Stack is empty: cannot execute pop.");
   } else {
      node *my_node_1 = s.top;
      node *my_node_2 = my_node_1;
      my_node_1 = my_node_1->below;
      
      d = my_node_2->data; //Here I'm assigning back the d variable
      
      free(my_node_2);
      
      s.top = my_node_1;
      if(my_node_1==NULL) s.base = NULL;
   }
   return s;
}

CodePudding user response:

For starters these unconditional memory allocations

stack stack_push(stack s){
   ...
   int *push_int = malloc(sizeof(int));
   float *push_float = malloc(sizeof(float));;
   char *push_char = malloc(sizeof(char));;
   char *push_char_arr = malloc(sizeof(char)*MAX_STRING_SIZE 1);
   //...

result in memory leaks because only one allocated object is indeed used in the stack.

The data member data of the structure struct _node has the type void *

struct _node{
   void *data;
   struct _node *below;
};

while the parameter d of the function stack_pop has the type void **

void **d

So this assignment

d = my_node_2->data;

does not make a great sense.

Instead you should write in main for example

     case 2:
        void *d = NULL; //d will contains the returned value.
        my_stack = stack_pop(my_stack, &d);     
        container *cont = (container*)d; 
        if ( cont != NULL ) printf("%d", cont->i); //SEGMENTATION FAULT ERROR HERE
        break;

And within the function stack_pop you should write

stack stack_pop(stack s, void **d){
   if(s.base == NULL && s.top == NULL){
      //Stack is empty
      puts("Stack is empty: cannot execute pop.");
      *d = NULL;
   } else {
      node *my_node_1 = s.top;
      node *my_node_2 = my_node_1;
      my_node_1 = my_node_1->below;
      
      *d = my_node_2->data; //Here I'm assigning back the d variable
      
      free(my_node_2);
      
      s.top = my_node_1;
      if(my_node_1==NULL) s.base = NULL;
   }
   return s;
}

As for your original code then the pointer d declared in main is passed to the function by value. As a result the function deals with a copy of the value of the pointer and changes of the copy do not influence on the value of the original pointer.

And you should free the allocated memory pointed to by the pointer d in main and by data members of the object pointed to by d.

Also it will be much better if objects of the structure type will be passed to functions by reference through pointers to them instead passing them themselves.

For example the declaration of the function stack_pop could look like

int stack_pop(stack *s, void **d);
  • Related