Shankar Narayanan
Shankar Narayanan

Reputation: 171

Issue with a generic stack library

I am trying to write a generic stack library[using arrays] which could allocate a stack for any element size and number of elements. I am trying the below code. First of all i get a warning saying that i am dereferencing a void pointer when used in memcpy.

Second is i am having some issue in the output that i am trying to print. Please help.

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

typedef struct _stk_
{
    int top;
    int elemsize;
    int numElem;
    void *array;
}stack;

stack *create_stack(int elemsize, int numElem)
{
    stack *stk_handle = malloc(sizeof(stack));

    if(!stk_handle)
    {
        printf("Malloc failed for stack handle\r\n");
        return NULL;
    }
    stk_handle->top = -1;
    stk_handle->elemsize = elemsize;
    stk_handle->numElem = numElem;
    stk_handle->array = calloc(elemsize, numElem);

    if(!(stk_handle->array))
    {
        printf("Malloc failed for stack\r\n");
        free(stk_handle);
        return NULL;
    }

    return stk_handle;
}

void push (stack *stk_handle, void *element)
{
    memcpy(&(stk_handle->array[++stk_handle->top]), element, stk_handle->elemsize);
    printf("Pushed element %s to stack. Top is %d\r\n", element, stk_handle->top);
}

void pop (stack *stk_handle, void *element)
{
    memcpy(element, &(stk_handle->array[stk_handle->top--]), stk_handle->elemsize);
    printf("Popped element %s from stack. Top is %d\r\n", element, stk_handle->top);
}

int main()
{
    stack *stk_handle = NULL;
    char string1[] = "close";
    char string2[] = "the";
    char string3[] = "door";
    char string4[6], string5[6],string6[6];

    stk_handle = create_stack(6, 5);
    push(stk_handle, &(string1));
    push(stk_handle, &(string2));
    push(stk_handle, &(string3));
    pop(stk_handle, string4);
    pop(stk_handle, string5);
    pop(stk_handle, string6);
    return 1;
}

When i compile I get below compilation warning.

$ gcc stack_lib.c
stack_lib.c: In function âpushâ:
stack_lib.c:39: warning: dereferencing âvoid *â pointer
stack_lib.c: In function âpopâ:
stack_lib.c:45: warning: dereferencing âvoid *â pointer

And when i run the program, I get below output:

Pushed element close to stack. Top is 0
Pushed element the to stack. Top is 1
Pushed element door to stack. Top is 2
Popped element door from stack. Top is 1
Popped element tdoor from stack. Top is 0
Popped element ctdoortdoor from stack. Top is -1

Please let me know where i am going wrong.

Upvotes: 3

Views: 181

Answers (2)

Lee Duhem
Lee Duhem

Reputation: 15121

  1. Those dereferencing void * pointer warnings could be fixed by using proper pointer arithmetic:

    void push (stack *stk_handle, void *element)
    {
            memcpy((char *)stk_handle->array + ++stk_handle->top * stk_handle->elemsize, element, stk_handle->elemsize);
            printf("Pushed element %s to stack. Top is %d\r\n", (char *)element, stk_handle->top);
    }
    
    void pop (stack *stk_handle, void *element)
    {
            memcpy(element, (char *)stk_handle->array + stk_handle->top-- * stk_handle->elemsize, stk_handle->elemsize);
            printf("Popped element %s from stack. Top is %d\r\n", (char *)element, stk_handle->top);
    }
    

    If you are using gcc, then the type-casting before stk_handle is unnecessary, see Pointer arithmetic for void pointer in C.

  2. The & operation in push(stk_handle, &(string1)); is unnecessary, you could just write

    push(stk_handle, string1);
    push(stk_handle, string2);
    push(stk_handle, string3);
    

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409176

Its the stk_handle->array[...] that's the void pointer dereference. Since the array member is a void pointer, you can't dereference it directly (either with the dereference operator * or using array-syntax like you do) without casting to a concrete type.

Remember that with array indexing the compiler uses the index multiplied with the base type to get the offset to the correct entry. When you have a void* what is the base type? void is not a valid base type by itself, so what should the compiler multiply the index with? It simply will not work.

My suggestion is to have a int8_t pointer instead, and then multiply the top with the element size:

typedef struct _stk_
{
    int top;
    int elemsize;
    int numElem;
    int8_t *array;
}stack;

...

memcpy(stk_handle->array + (++stk_handle->top * stk_handle->elmsize), ...);

Upvotes: 1

Related Questions