在C中创建一个用链表实现的通用堆栈

在C中创建一个用链表实现的通用堆栈,c,data-structures,stack,linked-list,function-pointers,C,Data Structures,Stack,Linked List,Function Pointers,我想创建一个通用堆栈。我想用一个链表来实现它 我创建了这个结构堆栈\u l: typedef struct stack { void * data; void (*copy)(void *o); struct stack *next; } stack_l; 我有一些问题: 结构的第二个字段是指向函数的指针,用于复制新数据(在函数Push中通过参数传递)。 功能推送的原型为: 栈顶推(栈顶,void*d) 我将指针传递到函数副本的方式正确吗 我必须在函数Push

我想创建一个通用堆栈。我想用一个链表来实现它

我创建了这个结构堆栈\u l

typedef struct stack
 {
   void * data;

   void (*copy)(void *o);

   struct stack *next;

 } stack_l;
我有一些问题:


  • 结构的第二个字段是指向函数的指针,用于复制新数据(在函数Push中通过参数传递)。 功能推送的原型为:
栈顶推(栈顶,void*d)

  • 我将指针传递到函数副本的方式正确吗
  • 我必须在函数Push中实现它

    • 是否有必要创建一个函数NewStack(例如)来对结构的字段进行日化,或者最好只有一个Push函数,如果堆栈为空,则创建第一个元素,如果至少有一个元素,则在顶部添加新元素

    • void*需要分配malloc吗

    首先,
    堆栈和
    堆栈不需要不同的标识符。现在,请回答您的问题:

    您的
    Push
    功能与
    stack\l
    中的
    copy
    字段的类型不兼容。如果你想在你的代码>结构> <代码>中包含一个指针(成员函数),使它看起来像C++,你仍然必须把你的对象传递给这些函数。 是的,您必须在某个地方实现您的功能,而这不能在
    struct stack
    的定义范围内。这意味着您确实需要某种构造函数(如果愿意,您可以称之为
    newStack
    )。构造函数必须至少初始化函数指针(如果您想保留它们)。如果您选择不保留这些函数指针,您可以按照您的建议,将初始化代码很好地放入
    push
    例程中:

    stack_l* stackPush(stack_l* head, void* content) {
      // head might be NULL, meaning the stack is "empty" or it might be an actual pointer
      // we don't care
      stack_l* const front = malloc(sizeof(stack_l));
      *front = (stack_l){.data = content, .next = head};
      return front;
    }
    
    请注意,您必须明确说明空堆栈是什么。因此,为了清晰起见,您可能需要实现一个构造函数:

    stack_l* stackCreateEmpty() {
      retun NULL;
    }
    
    甚至可能是一个析构函数:

    void stackDestroyEmpty(stack_l* s) {
      assert(s == NULL && "Tried to destroy non-empty stack.");
    }
    

    对于您的最后一个问题:如上所述,您必须使用
    malloc
    来获得容纳
    stack\l
    对象的空间,除此之外,您不需要为
    void*
    成员分配额外的空间,由于它是堆栈的一部分,显然我还创建了一个Pop函数来删除元素。谢谢你的评论。我只是不明白,如果将void*内容分配给.data=content的数据,是否有必要复制我的函数。也许我不理解。@Kyrol:你不必!正如我所说的,这只是为了清楚起见,所以堆栈实现的用户有一些接口需要保留。关于
    copy
    :由于堆栈只存储
    void
    指针(它存储指针的文本值,而不是指针指向的内容),因此不必实现复制功能,只需逐字复制指针即可。但是,如果确实要复制指针指向的对象,则必须为push函数提供一个自定义的copy参数,因为堆栈不可能知道其中存储了什么。希望这对您有所帮助,否则请询问。好的,很抱歉对构造函数产生误解!关于
    copy
    :好的,如果我使用最大泛型属性编写函数,我不需要该函数。但是,如果我在main中调用Push,并且我想在数据中存储一个int(例如),我需要这个函数,不是吗?另一件事:为什么要将front声明为
    const
    ?@Kyrol:换句话说,如果
    堆栈拥有数据,那么必须提供一些复制数据的方法(即,知道
    void*
    参数指向的语义和大小的东西)。但是,如果您希望堆栈只跟踪指针本身,则不需要复制机制。关于
    front
    ,我不打算更改指针,而且我有一个习惯,就是尽可能使所有内容都不可变且尽可能局部(可能是函数编程中的一些残余迷信)。这通常可以防止错误!