Search code examples
cstructstackdynamic-memory-allocationfunction-definition

Adding item to a stack make it crash


I am trying to implement on my own (in order to understand it better) the Stack data structure in C language.

Here is what I've got so far:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct stack{
    //Data_Strucure: Stack of intgers
    int *stack;
    int size_of_stack;
    int elem_in_stack;
};

struct stack *creat_stack(unsigned int);
int push(struct stack *, int);
int pop(struct stack *);
int empty(struct stack *);
int peek(struct stack *);

int main(int argc, char *argv[]){
    int new_elem = 13;
    struct stack *new_stack = creat_stack(5);

    printf("%d %d\n", new_stack->size_of_stack, new_stack->elem_in_stack);

    //Crashes from here
    push(new_stack, new_elem);
    printf("%d\n", new_stack->stack[new_stack->size_of_stack]);

}

struct stack *creat_stack(unsigned int size){
    struct stack tmp;
    struct stack *ret_stack = &tmp;

    if((ret_stack->stack = malloc(sizeof(int) * size)) == NULL){
        fprintf(stderr, "Unable to allocate memory for the Stack.\n");
        exit(1);
    }
    ret_stack->size_of_stack = size;
    ret_stack->elem_in_stack = 0;

    return ret_stack;
}

int push(struct stack *stack, int nw_elem){
    int pos = stack->size_of_stack - stack->elem_in_stack;
    if(stack->size_of_stack == 0)
        return 1;
    stack->stack[pos] = nw_elem;
}

The compiler returns me no error. Though I don't understand why it crashes after push() is called. Please, if possible, instead of solution code, can you just tell me where the error is? This way I can understand how it effect the whole program and try to solve it on my own (so next time won't happen again). Thanks is advance for any of your usefull answers.


Solution

  • At least the function creat_stack is incorrect.

    struct stack *creat_stack(unsigned int size){
        struct stack tmp;
        struct stack *ret_stack = &tmp;
        
        //...
    
        return ret_stack;
    }
    

    It returns a pointer to the local object tmp that will not be alive after exiting the function. So the returned pointer will be invalid and dereferencing such a pointer invokes undefined behavior.

    Instead you could return the object itself from the function. That is the function declaration could look like

    struct stack creat_stack(unsigned int size);
    

    And in main you can write

    struct stack new_stack = creat_stack(5);
    

    Also the function push does not change the data member elem_in_stack And again it invokes undefined behavior because when elem_in_stack is equal to 0 then the function tries to write to memory outside the dynamically allocated array. That is in this case pos is equal to size_of_stack.

    int push(struct stack *stack, int nw_elem){
        int pos = stack->size_of_stack - stack->elem_in_stack;
        if(stack->size_of_stack == 0)
            return 1;
        stack->stack[pos] = nw_elem;
    }