【问题标题】:Deleting all items from a queue从队列中删除所有项目
【发布时间】:2020-12-02 02:15:43
【问题描述】:

假设我有以下结构

typedef struct node {
    unsigned long data;
    struct node* next;
} node;

typedef struct queue {
    node* head;
    node* tail;
    int size;
    int capacity;
} queue;

queue* buildar()
{
    queue* arr = malloc(num * sizeof(queue));
    int i;
    for (i = 0; i < num; i++)
    {
        queue* r = malloc(sizeof(queue));
        r->head = NULL;
        r->tail = NULL;
        r->size = 0;
        r->capacity = assoc;
        arr[i] = *r;
    }
    return arr;
}

如何释放队列中的所有项目? 我已经尝试过这样做

    for (size_t i = 0; i < numberofsets; i++)
    {
        node* temp = arr[i].head;
        arr[i].head = arr[i].head->next;
        free(temp);
    }
    free(arr);

但它似乎不起作用。任何帮助表示赞赏。

【问题讨论】:

  • 您有一个队列数组,而不是一个队列。这真的是你想要的吗?
  • 是的,这正是我想要的@kaylum
  • 那么你需要一个遍历next指针的内部循环来释放每个节点。最后你需要free(queue[i])
  • 您的队列数组结构看起来不正确。或者至少不是很好。你应该有一个queue * 的数组,而不是queue 的数组。目前你有内存泄漏。在buildar 中,r 指针值丢失,因此永远无法释放。
  • 请详细描述“它似乎不起作用”。在您分配队列根数组的分配循环中,您不需要内部malloc();删除它并将所有r-&gt; 替换为arr[i]。对于您的free() 循环,您只释放每个队列中的第一个项目;您需要按照next 来释放每个队列中的所有内容。

标签: c data-structures queue


【解决方案1】:

您正在寻找一组数组(我认为/希望)。基本上,您想从一个“主”数组创建所有可索引的n 队列(这是一个词吗?)。

所以你是这样看的:

idx
of
big
arry
_________________________________  
|000|   ----->  [ one big queue ]  
|001|   ----->  [ one big queue ]  
|002|   ----->  [ one big queue ]  
|003|   ----->  [ one big queue ]  
|004|   ----->  [ one big queue ]  
|...|   ----->  .................   
|nth|   ----->  [ one big queue ]  
_________________________________  
#include <stdlib.h>


typedef struct node
{
    unsigned long data;
    struct node*  next;
}
node;

typedef struct queue
{
    int   size;
    int   capacity;
    node* head;
    node* tail;
    
}
queue;


queue** build_queue(int num  ,
                    int assoc
                   )
{
    //here you create an array of arrays
    //result is an array of pointers, each pointer going to a separate array 
    queue** result = malloc(num * sizeof(queue*));
    
    int i;
    for (i = 0; i < num; i++)
    {
        queue* q    = malloc(sizeof(queue));  //memory for actual queue
        result[i]   = q;

        q->head     = NULL;
        q->tail     = NULL;
        q->size     = 0;
        q->capacity = assoc;
    }

    return result;
}



void free_queues(int     num_queues,
                 queue** qs
                )
{
    int i;
    for (i = 0; i < num_queues; i++)
    {
       /*
        * NOTE: you must use a while loop here to FIRST free the linked list qs[i]
        * node* head = qs[i]->head;
        * while(head != qs[i]->tail)
        * {
        *     node* temp = head->next;
              free(head);
              head = temp;
        * }
        * free(qs[i]->tail);
        */
       free(qs[i]);  //frees the actual queue struct   
    }
    free(qs);        //frees the array of pointers to queues
}



int main(void)
{
   int num   = 5;
   int assoc = 4;
 
   queue** qs = build_queue(num, assoc);
   free_queues(num, qs);

   return 1;
}

最后,使用valgrind 来检查是否有泄漏。对于上述解决方案:

$ gcc please_work.c
$ valgrind ./a.out 
==5974== Memcheck, a memory error detector
==5974== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5974== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==5974== Command: ./a.out
==5974== 
==5974== 
==5974== HEAP SUMMARY:
==5974==     in use at exit: 0 bytes in 0 blocks
==5974==   total heap usage: 6 allocs, 6 frees, 160 bytes allocated
==5974== 
==5974== All heap blocks were freed -- no leaks are possible
==5974== 
==5974== For lists of detected and suppressed errors, rerun with: -s
==5974== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

【讨论】:

    【解决方案2】:

    很难猜出“似乎不起作用”是什么意思,但代码存在几个问题。

    buildar() 中,您使用了两个未定义的变量。您可能将它们作为全局变量,但您可能希望它们作为函数的参数。您还会泄漏内存,因为您 malloc() 一个新链接,初始化它,将那里的值复制到数组中,然后丢弃分配的内存,现在永远不会被释放。

    // added num & assoc here--assuming it should be a parameter
    queue* buildar(int num, int assoc) 
    {
        queue* arr = malloc(num * sizeof(queue));
        int i;
        for (i = 0; i < num; i++)
        {
            // This will leak memory. You allocate a root
            // that you initialise, then you copy the data
            // and then you throw away the allocated memory
            // when you update r, or it goes out of scope
            queue* r = malloc(sizeof(queue));
            r->head = NULL;
            r->tail = NULL;
            r->size = 0;
            r->capacity = assoc;
            arr[i] = *r;
        }
        return arr;
    }
    

    由于您已经在数组中有根链接,您可以只更新它们,并避免 malloc():

    queue* buildar(int num, int assoc) 
    {
        queue* arr = malloc(num * sizeof *arr);
        for (int i = 0; i < num; i++)
        {
            arr[i].head = NULL;
            arr[i].tail = NULL;
            arr[i].size = 0;
            arr[i].capacity = assoc;
        }
        return arr;
    }
    

    在释放代码中,如果根节点是新初始化的,它们的head指针是NULL。当您取消引用它们以获取 head-&gt;next 时,这将是一个问题。从技术上讲,取消引用 NULL 是未定义的行为,但在实践中,这将是一个分段错误,会使您的程序崩溃。如果每个条目有多个节点,则会泄漏内存。在根之后释放第一个,然后将根的头指向下一个,然后释放包含根的数组。

    据我所知,如果每个索引只有一个节点(根之后),代码将按预期工作,但如果为零则崩溃,如果有更多则泄漏。如果应该有可变数量的节点,那是“似乎不起作用”的一个来源。可能是这样吗?

    void free_queues(queue *arr, int numberofsets)
    {
      for (size_t i = 0; i < numberofsets; i++)
      {
        node* temp = arr[i].head;
        // if the queue was empty, arr[i].head->next
        // dereferences a NULL pointer, which is
        // undefined behaviour
        arr[i].head = arr[i].head->next;
        // This only removes one link from the queue.
        // If there are more, you leak memory when you
        // free arr below
        free(temp);
      }
      free(arr);
    }
    

    如果是这样的话,你可能想要这样的东西:

    void free_queues(queue *arr, int numberofsets)
    {
      for (size_t i = 0; i < numberofsets; i++) {
        node* temp = arr[i].head, *next;
        while (temp) {
          next = temp->next;
          free(temp);
          temp = next;
        }
      }
      free(arr);
    }
    

    【讨论】:

    • 我想知道这是否是 OP 真正想要的。他似乎确信内部 malloc 是必要的。我认为这是一个缓存模拟器任务,他们正在尝试模拟 L1 缓存关联性。
    • 可能是这样,但现在它除了泄漏内存之外什么也没做。也许它应该是一个指向节点的指针数组,那么呢?
    • 我也是这么想的。指向队列的指针数组。他们将一个元素添加到队列中,然后增加计数r-&gt;size += 1。哦,伙计..我在这上面花了太多时间。您对 AlphaFold 感到兴奋吗?
    • @slmatrix AlohaFold islretth 很酷,但我自己没有研究过蛋白质折叠,所以我真的不知道它在这个问题上的优势所在
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    • 2011-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-20
    • 1970-01-01
    相关资源
    最近更新 更多