【问题标题】:C - How to iterate through an ADT struct?C - 如何遍历 ADT 结构?
【发布时间】:2026-02-01 15:55:01
【问题描述】:

我正在为一项学校作业制作一套 ADT,而且我非常接近完成。但是,对于如何遍历结构中的各个项目,我遇到了一些困难: set 结构的“元素”成员必须是一个 void 指针,如果它是 int 类型,我可以set->element[i]。对替代品有什么建议吗?

struct set
{
    void *element;
    int size;
    cmpfunc_t cmpfunc;
    set_t *start;
    set_t *next;
};

int set_contains(set_t *set, void *elem)
{
    for(int i = 0;i<set->size;++i)
      if(set->element[i] == elem)
        return 1;

    return 0;
}

【问题讨论】:

  • 您的意思是void **element;?你不能这样取消引用,否则......
  • 对不起,空指针是我的意思。编辑固定。
  • *start*next 的用途是什么? cmpfunc_t是怎么定义的? struct set 是针对单个元素、一组相同种类的元素还是针对许多不同种类的元素?
  • 看起来您正在尝试实现结构的链接列表,并且想要遍历列表以检查指针是否匹配,但是元素指针可以是指向数组的指针,其中大小的条目数?还是 size 是指向的不是数组的元素的大小?
  • 像这样的带有 void 指针的 ADT 非常“老派”——无论是积极的还是消极的。积极的,因为你实际上被教导编写 ADT,这是 C 中的好习惯。消极的因为使用 void 指针的泛型编程是不安全的并且通常是混乱的。编写类似代码的现代方法是使用_Generic 或使用包含特定类型行为的回调函数。

标签: c struct abstract-data-type


【解决方案1】:

您的 ADT 结构并没有多大意义;看起来您已经尝试过杂交不同的设计模式,即使用数组来保存集合元素,以及使用链表来保存集合。

我将随意修改结构,使其更符合任一模式。首先,typedef 的隐藏信息 -> 尽可能避免它们。

第一种模式:使用元素数组

struct set {
  void **elements;              /* array of elements    */
  int nElem;                    /* array count          */
  size_t elemSize;              /* size of element type */
  int(*cmpFunc)(void*, void*);  /* equality comparison  */
};

elemSize 字段用于在不知道数据类型的情况下分配和复制新元素。这对两种模式和一般的通用 ADT 都很常见。要遍历此集合,请使用:

int set_contains(struct set *pSet, void *elem) {
  for (int i = 0; i < pSet->nElem; ++i) {
    if (pSet->cmpFunc(pSet->elements[i], elem))
      return 1;
  }
  return 0;
}

第二种模式:使用链表来表示集合

struct node {
  void *data;         /* element data      */
  struct node *next;  /* next node in list */
};

struct set{
  struct node *head;            /* first element       */
  size_t elemSize;              /* size of data type   */
  int(*cmpFunc)(void*, void*);  /* equality comparison */
};

元素大小和比较函数是给定集合的属性,而不是包含在该集合中的数据,因此它们是在set结构上定义的,而不是node结构上定义的,它只定义了数据和关联的链接。要遍历此集合,请使用:

int set_contains(struct set *pSet, void *elem) {
  struct node *head = pSet->head;
  while(head) {
    if (pSet->cmpFunc(head->data, elem))
      return 1;
    head = head->next;
  }
  return 0;
}

【讨论】: