Search code examples
ctypesstackansi-c

Complex generic stack


I have been assigned to program a generic stack in ANSI C. It is meant to be for primitive datatypes. Until here there was no big problem whatsoever.

Afterwards I was asked to reprogram my application so that even complex data types can be used on my stack. I have searched and researched for the last week and I found nothing that could be helpful enough.

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stddef.h>
#include "genstacklib.h"
void (*freefn) (void*);

/*
 * ToDo
 */
void GenStackNew(genStack *s, int elemSize, void (*freefunk) (void*))
{
    s->elems = malloc (elemSize * GenStackInitialAllocationSize);
    freefn = freefunk;
    assert (s->elems != NULL);
    s->elemSize = elemSize;
    s->logLength = 0;
    s->allocLength = GenStackInitialAllocationSize;
}
/* 
 * ULStackPush adds an element to the stack and allocates new memory if
 * needed. If there is not enough memory, ULStackPush does nothing.
 */
void GenStackPush (genStack *s, const void *elemAddr)
{
    /*assert (sizeof(*elemAddr) == s->elemSize);*/
    assert (s->elems != NULL);

    if (s->logLength == s->allocLength)
    {
        void *temp = NULL;

        temp = realloc (s->elems, 2 * s->allocLength * s->elemSize);
        assert (temp != NULL);
        s->allocLength = 2 * s->allocLength;
        s->elems = temp;
    }
    memcpy(currentval(s), elemAddr, s->elemSize);
    s->logLength = s->logLength + 1;
}

void GenStackPop (genStack *s, const void *elemAddr)
{
    assert (s->elems != NULL);
    assert (s->logLength != 0);
    (s->logLength)--;
    memcpy((void *)elemAddr, currentval(s), s->elemSize);
}

void *currentval(genStack *s)
{
    assert (s->elems != NULL);
    return ((size_t*)s->elems + s->logLength * s->elemSize);
}

bool GenStackEmpty (const genStack *s)
{
    assert (s->elems != NULL);
    return s->logLength == 0;
}

void GenStackDispose (genStack *s)
{
    assert (s->elems != NULL);
    s->logLength = 0;
    free (s->elems);
    freefn();
}
/*
 * ToDO
 */
void *freefn (void *) {
    free 

And my header data is:

#ifndef GENSTACKLIB_H
#define GENSTACKLIB_H

#include <stdbool.h>
#define GenStackInitialAllocationSize 4

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

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

In the first block of code, I believe that what has to be done is in the ToDo markings. How can I make it to use my stack for complex data types?

Thanks in advance


Solution

  • I dont see any problem with "complex" types like strings... there is no real difference bewteen pointer to string and pointer to int. So just store pointers (or pointers to pointers) and that should work.

    So instead of element to be "int".. element is pointer to pointer.

    Basic idea in form of very "pseudo" C code

    typedef struct Wrapper 
    {
     void * primitiveData;
    } Wrapper;
    
    
    void PrimitivePush(void * data)
    {
     Wrapper * w = malloc();
     w->primitiveData = malloc();
     memcpy(w->primitiveData, data);
    
     ClassicComplexTypePush(&w)
    }
    
    ClassicComplexTypePush(void ** data)
    {
      push data to stack
    }