Question

I am trying to implement a generic stack in C using void pointers. This is not anything big, just for fun and learning. It is working with int and float as expected. But the problem I am facing is with char *, i.e. strings. It is not copying the address of the string instead trying to copy the actual string upto 4 bytes(as in my system pointer size is 4 bytes).

How to tell C to copy address of the string not the actual string, if possible, with out breaking the functionality of int and float already working?

My implementation so far is as follows,


typedef struct{
        int top;
        void *data;
        int capacity;
        size_t ele_size;
}stack_t;

int stack_init(stack_t *s, int capacity, size_t ele_size)
{
        /*  Initializes the stack with the given capacity
         *  @param s: Pointer to stack_t type variable
         *  @param capacity: capacity of the stack to be created
         *  Returns : Zero if succesful in allocating memory to the stack,
         *              -1 Otherwise
         */
        s->top = -1;
        s->capacity = capacity;
        s->ele_size = ele_size;
        s->data = calloc(s->capacity, s->ele_size);
        if (s-> data != NULL || s->capacity == 0) {
                return 0;
        } else {
                return -1;
        }
}

int stack_push(stack_t *s, void *x)
{
        /*  Pushes an element on to the stack
         *  @param s: Pointer to stack_t type variable
         *  @param x: Value to Push on to the stack
         *  Returns : Zero if stack is not full when stack_push() is called,
         *              -1 Otherwise
         */
        if (stack_len(s) capacity) {
                s->top++;
                memcpy(s->data + s->ele_size * s->top, x, s->ele_size);
                return 0;
        } else {
                return -1;
        }
}

int stack_pop(stack_t *s, void *value)
{
        /*  Value that is popped from the stack is placed in value parameter,
         *  @param s: Pointer to stack_t type variable
         *  @param x: Pointer to a variable to store the value popped from the 
                        stack
         *  Returns:  Zero if stack is not empty when stack_pop() is called,
         *              -1 Otherwise
         */
        if (stack_len(s) > 0) {
                memcpy(value, s->data + s->ele_size * s->top, s->ele_size);
                s->top--;
                return 0;
        } else {
                return -1;
        }
}

For complete implementation of stack please refer here

Usage of the above stack is as follows: Actually there is lot of unrelated stuff like using pseudo random number generator to insert random numbers into stack.



#include"../src/stack.h"

START_TEST(int_push_pop)
{
        stack_t s;
        int n = random() % 60267;
        int *a = calloc(n, sizeof (int));
        ck_assert_int_eq(stack_init(&s, n, sizeof (int)), 0);
        int i;
        for (i = 0; i = 0; i--) {
                int value;
                int x = stack_pop(&s, &value);
                ck_assert_int_eq(x, 0);
                ck_assert_int_eq(value, a[i]);
                x = stack_len(&s);
                ck_assert_int_eq(x, i);
        }
        stack_clear(&s);
        stack_destroy(&s);
}

END_TEST

START_TEST(float_push_pop)
{
/* similar to int_push_pop, so ignored here. */
}

END_TEST


START_TEST(string_push_pop)
{
        stack_t s;

        char *str = "stack overflow";
        stack_push(&s, str);
        char **popval = malloc(sizeof(char *));
        stack_pop(&s, popval);
        printf("%s\n", popval);

        stack_destroy(&s);

}

END_TEST


Suite* stack_suite()
{
        Suite *s = suite_create("Stack");

        TCase *tc_int = tcase_create("int");
        /* Stack int data type Test Case*/

        TCase *tc_float = tcase_create("float");
        /* Stack float data type Test Case*/

        tcase_add_test(tc_int, int_push_pop);
        tcase_add_test(tc_float, float_push_pop);

        suite_add_tcase(s, tc_int);
        suite_add_tcase(s, tc_float);

        return s;
}


int main()
{
        int number_failed;
        Suite *s = stack_suite();
        SRunner *sr = srunner_create(s);
        srunner_run_all(sr, CK_NORMAL);
        number_failed = srunner_ntests_failed(sr);
        srunner_free(sr);

        return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

Was it helpful?

Solution

Since stack_push() and stack_pop() functions are taking a void* pointer, you will need to pass a pointer to the character array(string) that needs to be pushed and not the char array itself. e.g. if you declare your string as

char str[] = "hello world";

you will have to call the function as

stack_push(s,&str);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top