Bfcm
Bfcm

Reputation: 2746

Void-pointers in generic stack implementation (Plain C)

I'm trying to make a generic stack in plain C and I have some problems with pointers and no idea where is the problem.

Here's the structure and functions, where I have problems:

typedef struct{
    void *elems; 
    int elemSize; 
    int logLength; 
    int allocLength;
} genStack;

void GenStackPush(genStack *s, const void *elemAddr); 
void GenStackPop(genStack *s, void *elemAddr);

That's the implementation:

void GenStackPush(genStack *s, const void *elemAddr)
{
    s->elems[s->logLength] = elemAddr;
    s->logLength++;
}

void GenStackPop(genStack *s, void *elemAddr)
{
      s->logLength--;
      elemAddr = s->elems[s->logLength];
}

The usage should look like this:

int val; 
genStack IntegerStack;
for (val = 0; val < 6; val++)
    GenStackPush(&IntegerStack, &val);

GenStackPop(&IntegerStack, &val); 
printf("Popped: %d\n",val);

And here are the problems I get:

genstacklib.c: In function ‘GenStackPush’:
genstacklib.c:60:10: warning: dereferencing ‘void *’ pointer [enabled by default]
genstacklib.c:60:2: error: invalid use of void expression
genstacklib.c: In function ‘GenStackPop’:
genstacklib.c:72:23: warning: dereferencing ‘void *’ pointer [enabled by default]
genstacklib.c:72:13: error: void value not ignored as it ought to be

I have tried already several ways to fix the code, but none of them worked. Thanks.

==========================================================================

So, guys, thanks for help! Now it compiles, but I have changed an API, which was given by our Professor. There was also the problem with 'const' qualifier, so I deleted them. Not my code looks like this:

genstacklib.h:

#ifndef GENSTACKLIB_H
#define GENSTACKLIB_H
#define GenStackInitialAlocationSize 4

typedef struct{
    void** elems;
    int elemSize;
    int logLength;
    int allocLength;
}genStack;

void GenStackNew(genStack *s,int elemSize);
void GenStackDispose(genStack *s);
int GenStackEmpty(const genStack *s);
void GenStackPush(genStack *s, void *elemAddr);
void GenStackPop(genStack *s, void *elemAddr);

#endif

genstacklib.c:

#include <stdlib.h>
#include <stdio.h>
#include "genstacklib.h"

void GenStackNew(genStack *s,int elemSize)
{
    void** newElems;

    /* Allocate a new array to hold the contents. */
    newElems = (void**) malloc(elemSize * GenStackInitialAlocationSize);

    if (newElems == NULL)
    {
        fprintf(stderr, "Error with allocating the stack.\n");
        exit(1); /* Exit, returning error code. */
    }
    s->elems = newElems;
    s->allocLength = GenStackInitialAlocationSize;
    s->logLength = 0; /*is empty*/

}

void GenStackDispose(genStack *s)
{
    s->allocLength = 0;
    free(s->elems);
}

int GenStackEmpty(const genStack *s)
{
    return s->logLength == 0;
}

void GenStackPush(genStack *s, void *elemAddr)
{
    s->elems[s->logLength] = elemAddr;
    s->logLength++;
}

void GenStackPop(genStack *s, void *elemAddr)
{
      s->logLength--;
      elemAddr = s->elems[s->logLength];
}

If you have any ideas to improve it or something to say about it, I would hear with pleasure. :D

Upvotes: 1

Views: 5066

Answers (4)

yaronli
yaronli

Reputation: 705

The problem is s->elems[s->logLength] :

First, the member variable void *elems use to store the element address (void *), array of the element (void ), so the type of the elems should be (void *), and you should allocate the memory to store the address.

You can allocate memory by the following ways:

void * elems[MAX_STACK_SIZE];

OR

void ** elems    
s->elems = (void**)malloc(MAX_STACK_SIZE*sizeof(void*)); // and allocate it before use it.

Upvotes: 0

JeremyP
JeremyP

Reputation: 86651

elems has the wrong type. If you declare it as void* the compiler does not know how big the things it points to are. So it can't do pointer arithmetic or array subscripting on it or even dereference what it points to.

Conceptually elems is an array of the things that you put on the stack. What do you put on the stack? Pointers - declared as void*. So elems should be an array of void* objects. You can declare it like this

typedef struct{
    void *elems[STACK_SIZE]; 
    int elemSize; 
    int logLength; 
    int allocLength;
} genStack;

which will reserve space in the struct for the array (making the struct itself very big), or you can declare it as a pointer to void* i.e. void**

typedef struct{
    void **elems; 
    int elemSize; 
    int logLength; 
    int allocLength;
} genStack;

If you go for this option, you then have to manually allocate the memory

genStack* genStackAlloc()
{
    genStack* ret = calloc(1, sizeof *ret);
    ret->elemns = calloc(STACK_SIZE, sizeof(void*));
    // rest of the initialisation

    return ret;
}

And of course, you'll have to manually free the memory when you dispose of the stack.

Upvotes: 1

P.P
P.P

Reputation: 121387

you are trying to dereference void pointer without typecasting to some other type which causing the problem.

Upvotes: 3

Scott Hunter
Scott Hunter

Reputation: 49803

elems is declared as a pointer to a void, where I think you want it to be a pointer to a void*.

Upvotes: 0

Related Questions