复杂的通用堆栈

时间:2014-04-23 10:49:52

标签: c types stack ansi

我被指派在ANSI C中编写通用堆栈。它适用于原始数据类型。直到这里,没有任何大问题。

之后我被要求重新编程我的应用程序,以便即使是复杂的数据类型也可以在我的堆栈上使用。我在上周进行了搜索和研究,但没有发现任何有用的东西。

#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 

我的标题数据是:

#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

在第一段代码中,我认为必须要做的是在ToDo标记中。 如何使用我的堆栈来处理复杂的数据类型?

提前致谢

2 个答案:

答案 0 :(得分:0)

我没有看到像字符串这样的“复杂”类型有任何问题...指向字符串和指向int的指针之间没有真正的区别。所以只需存储指针(或指针指针),这应该有用。

因此,元素不是“int”..元素是指向指针的指针。

非常“伪”C代码形式的基本思想

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
}

答案 1 :(得分:0)

Consider using a singularly linked list for implementation, since when 

使用堆栈,我们不知道可能需要多少项目。

使用字节*或(char *)来存储内存的内容,而不是void *(这也可以,但我们可能需要填充分配,以包含结构)

将内存复制到新的分配中,该分配被压入堆栈,   然后删除pop上使用的内容。

  • 每个节点必须属于同一类型,或者至少大小相同, 使用错误类型的错误可能是不受欢迎的

  • pop可用于通过传递检查堆栈是否为空(NULL) 或者通过引用你想要设置的内存来实际弹出堆栈。

    typedef unsigned char byte;
    

创建将用于跟踪堆栈的结构

    struct gStackNode {
        byte *data; 
        struct gStackNode *next;
    };

    struct gStack {
        unsigned size;
        struct gStackNode *head;
    };

初始化堆栈,包括我们将使用的类型的大小

    void stack_initalize(struct gStack *stk, unsigned size) {
        if (!stk)
            return;
        stk->size = size;
        stk->head = (void*)0;
    }

总是,我们需要手动释放堆栈,以防万一没有弹出

    void stack_free(struct gStack *stk) {
        if (!stk)
            return;
        struct gStackNode *temp;

        /* step through the remaining stack, deleting each item */

        while(stk->head) {
            temp = stk->head->next;
            free((byte*)stk->head->data);
            free((struct gStackNode *)stk->head);
            stk->head = temp;
        }
    }

将项目推入堆栈

    void stack_push(struct gStack *stk, void *data) {

        struct gStackNode *node = (struct gStackNode*)malloc(sizeof(struct gStackNode));
        struct gStackNode *temp = stk->head;

        node->next = temp;

        node->data = (byte*)malloc(sizeof(byte)*(stk->size));

        byte * src = (char*)(data);
        byte * dest = (char*)(node->data);

        unsigned n = stk->size;

        /* fill the new allocation with source data */

        for(;n;n--)
            *(dest++) = *(src++);

        /* the node becomes the new head */

        stk->head = node;

    }

有时我们不想使用局部变量,即:stack_pop_(stack,&amp; type)我们可以使用stack_push_arg_no_ref(stack,10)。

    void stack_push_arg_no_ref(struct gStack *stk, void *data) {
        stack_push(stk, &data);
    }

现在我们可以弹出,并使用相同的方式来查看,传递(NULL)数据将导致窥视, 如果堆栈中有项目则返回(1),如果空白则返回(0)

    int stack_pop(struct gStack *stk, void * data) {
        if (!stk)
            return 0;
        if (!stk->head)
            return 0;

        if (data == (void*)0) {
            /*  
                simply check to see if the stack is empty or not
                don't actually pop the stack
            */
            return ((!stk->head == (void*)0));
        } else {
            struct gStackNode *next = stk->head->next;
            struct gStackNode *node = stk->head;

            unsigned i;
            byte *c_temp = (byte*)data;
            for(i=0;i<stk->size;i++)
                *c_temp++ = node->data[i];

            free((byte*)node->data);
            free((struct gStackNode*)node);
            stk->head = next;
        }

}

最后我们可以实现堆栈

使用任何ANSI C数据类型

  • 需要修复字符串的大小

  • 结构也可以使用

使用字符串

  • 注意,对于此示例,字符串需要以NULL结尾 可以使用非NULL终止字符串

    char ta[32] = "ta: text 1";
    char tb[32] = "tb: text 2";
    char tc[32];
    
    struct gStack stack_char; stack_initalize(&stack_char, sizeof(ta));
    
    stack_push(&stack_char, ta);
    stack_push(&stack_char, tb);
    
    while (stack_pop(&stack_char, &tc))
        printf("%s\n", tc);
    

一定要释放堆栈

    stack_free(&stack_char);

使用整数

    int a = 120, b = -32, c;

    struct gStack stack_int; stack_initalize(&stack_int, sizeof(int));

    stack_push(&stack_int, &a);
    stack_push(&stack_int, &b);

    /* or we can use */

    stack_push_arg_no_ref(&stack_int, 1776);

    /* we can now see the contents of the stack */

    while (stack_pop(&stack_int, &c))
        printf("%d\n", c);


    stack_free(&stack_int);