C语言 复杂泛型堆栈

mlmc2os5  于 2023-03-28  发布在  其他
关注(0)|答案(2)|浏览(85)

我被指派用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

我的header数据是:

#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标记中。我如何才能将堆栈用于复杂的数据类型?
先谢了

zkure5ic

zkure5ic1#

我不认为像字符串这样的“复杂”类型有任何问题......字符串指针和整型指针之间没有真实的的区别。所以只要存储指针(或指针指针)就可以了。
因此,元素不是“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
}
hsvhsicv

hsvhsicv2#

Consider using a singularly linked list for implementation, since when

使用堆栈,我们不知道可能需要多少项。
使用byte* 或(char*)来存储内存的内容,而不是void*(void * 也可以工作,但是我们可能需要填充分配,以包含结构体)
将内存复制到一个新的分配中,该分配被推送到堆栈上,然后在弹出时删除已使用的内存。

  • 每个节点必须具有相同的类型或至少相同的大小,尽管使用错误类型的错误可能是不希望的
  • 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,&type)我们可以使用stack_push_arg_no_ref(stack,10)。

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

现在我们可以弹出,并使用相同的peek,传递(NULL)到数据将导致一个peek,返回(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);

相关问题