【问题标题】:Freeing memory in C: Queue在 C: 队列中释放内存
【发布时间】:2013-11-17 19:33:18
【问题描述】:
void insert_queue (queue *this, queue_item_t item) {

   //Inserts a new item at the end of queue.
   queue_node *temp = malloc(sizeof (struct queue_node));
   temp->item = item;

   if (isempty_queue(this)) this->front = temp; 
   else this->rear->link = temp;
   this->rear = temp;
   //free(temp);
}

queue_item_t remove_queue (queue *this) {
   assert (! isempty_queue (this));
   //This removes the first item from queue.
   queue_item_t temp = this->front->item;
   this->front = this->front->link;
   return temp;
}

当我尝试释放“临时”时,我收到了段错误错误。我应该在使用后释放一个节点,对吧?那么,在这种情况下如何防止内存泄漏呢?有任何想法吗? 谢谢。

当我删除 free(temp) 时,一切正常,但我遇到了内存泄漏。如果它不属于此功能,我不确定在哪里释放。我还添加了删除功能。 free 应该进去吗?

编辑编辑:谢谢大家,这是我更新的代码。

queue_item_t remove_queue (queue *this) {
   assert (! isempty_queue (this));

   queue_node *temp = this->front;
   queue_item_t rVal = temp->item;

   //Moves on to the next one.
   this->front = this->front->link;
   //Free the unlinked node.
   //free(temp->item); <<<<---- This causes program to fail.
   free(temp);
   return rVal;
}

内存泄漏仍在发生。

【问题讨论】:

  • 想想如果 this->rear == this->front in remove_queue 会发生什么。
  • @CharlieBurns +1 ,注意他不必检查 那个 比较,但他必须检查 something。如果this-&gt;front == nullptr 在推进之后,this-&gt;rear = nullptr; 是要采取的行动。

标签: c memory-leaks malloc free


【解决方案1】:

insert_queue 完成时,您还没有完成使用节点。 insert_queue 例程使用temp 来保存指向节点的指针,insert_queue 在返回时使用temp 完成,但节点本身是链表的一部分,因此它正在使用中。

remove_queue 将节点从列表中删除时,您就完成了使用该节点。 remove_queue 应该将指向节点的指针传递给free 以释放其内存。

不要将temp 视为一个节点。它只是一个临时保存指向节点的指针的对象。节点本身是一个独立的东西。

【讨论】:

  • 感谢大家的帮助,但我还是没明白。当我已经从队列中删除它时,如何访问该临时指针?
  • @Raymond 希望您了解queue_node 是一个容器。它包含两件事:您正在排队的数据元素,以及指向下一个 queue_node 的指针(如果它是队列中的最后一个节点,则为 null)。为临时节点分配内存并设置其数据后,您可以通过指针分配将其链接 到队列。链接后,队列“拥有”该节点,直到稍后以remove_queue 弹出它。因此,不需要释放。 free(temp)insert_queue() 中根本不需要。
【解决方案2】:

好吧,如果您要创建和插入一个新队列,为什么要删除它?请记住,当您使用 malloc() 时,您会保留一些与您所在的块无关的数据。 Free() 是您用来销毁由 malloc() 创建的内存的东西。所有本地范围的(不是用 malloc 创建的)数据/变量将在它们被尊重的块结束时自动销毁。使用 malloc() 创建的数据(在大多数情况下)不会。

void insert_queue (queue *this, queue_item_t item)
{
    //Inserts a new item at the end of queue.
    queue_node *temp = malloc(sizeof (struct queue_node));
    temp->item = item;

    if (isempty_queue(this))
        this->front = temp; 
    else
        this->rear->link = temp;
    this->rear = temp;
    //free(temp);    // remember tmp is still referring to
                               // the node, so you will be erasing the
                               // node you just put inside the queue.

}     // end of code block. Variable *temp will be
      // automatically freed from memory, but
      // its malloc'd data will not. This is good
      // because its data is being used inside our
      // queue, until it is removed with remove_queue().

稍后在您的删除函数中,您可以使用 free 删除“temp”(实际上是使用 malloc() 分配的内存)。或者你可以使用 free(remove_queue(&myq)),它会产生完全相同的结果,因为我们正在处理指针。

【讨论】:

    【解决方案3】:

    首先,“this”是 c++ 中的一个关键字。如果你问我,你也不应该在 c-context 中使用它——只是为了避免误解。

    第二个队列是一个项目、请求、人或某物在最后排队,并在时间到时早或晚从前面移除(dequed)。您似乎可以将其实现为链表。

    下一个 queue_item_t 项目在这里作为原始值的副本分配到堆栈上,因为我看不到它是一个指针,它是在分配给它的内存中的指针,它将在关闭时被删除}。

    如果变量 temp 实际上具有 newQueueNode 之类的含义,我不会调用它。有意义的应用程序/类/变量/函数名称是注释代码的最佳方式之一。

    最后评论,选择的return and pass by value没有ok参数,否则你会遇到无法返回副本的问题(size==0见我的例子),没办法说出错的函数的用户(在这种情况下队列为空)

    这是我的(快速生成和测试的)针对您的问题的最低解决方案:

    #include <stdlib.h>
    #include <stdio.h>
    
    struct queue_item_t
    {
        int exampleItemData;
    };
    
    struct queue_node
    {
        struct queue_item_t *item;
        struct queue_node *next;
    };
    
    struct queue
    {
        struct queue_node *firstItem;
        struct queue_node *lastItem;
        int size;
    };
    
    
    struct queue* createQueue()
    {
        struct queue *queuePtr = (struct queue *)malloc(sizeof (struct queue));
        queuePtr->firstItem = NULL;
        queuePtr->lastItem = NULL;
        queuePtr->size = 0;
        return queuePtr;
    }
    
    void queue(struct queue* queueData, struct queue_item_t itemToQueue)
    {
        // Create new node
        struct queue_node* newNode = (struct queue_node*)malloc(sizeof(struct queue_node));
    
        // Create new item
        newNode->item = (struct queue_item_t*)malloc(sizeof(struct queue_item_t));
    
        // Copy the item data from itemToQueue that will be deleted on the end of this function
        newNode->item->exampleItemData = itemToQueue.exampleItemData;
    
        // Insert the item into the queue
        if(0 == queueData->size)
        {
            queueData->firstItem = newNode;
            queueData->lastItem = newNode;
            newNode->next = newNode;
        }
        else
        {
            queueData->lastItem->next = newNode;
            queueData->lastItem = newNode;
        }
    
        queueData->size += 1;
    
        // ! itemToQueue will deleted here we must have a copy of the data in the queue }
    }
    
    struct queue_item_t dequeue(struct queue* queueData)
    {
        struct queue_item_t item;
    
        if (1 > queueData->size)
        {
            // !!! Serious problem if this happens:
            // What will you return, an initialized queue_item_t?
            // You can not return a null pointer ...
            // Better you write ok to a boolean comming in ass parameter or something
        }
        else if(1 == queueData->size)
        {
            item.exampleItemData = queueData->firstItem->item->exampleItemData;
    
            free(queueData->firstItem->item);
            free(queueData->firstItem);
            queueData->firstItem = NULL;
            queueData->lastItem = NULL;
        }
        else if(2 == queueData->size)
        {
            item.exampleItemData = queueData->firstItem->item->exampleItemData;
    
            struct queue_node* dequeuedNode = queueData->firstItem;
            queueData->firstItem = dequeuedNode->next;
            queueData->lastItem = dequeuedNode->next;
            free(dequeuedNode->item);
            free(dequeuedNode);
        }
        else if (1 < queueData->size)
        {
            item.exampleItemData = queueData->firstItem->item->exampleItemData;
    
            struct queue_node* dequeuedNode = queueData->firstItem;
            queueData->firstItem = dequeuedNode->next;
            free(dequeuedNode->item);
            free(dequeuedNode);
        }
    
        queueData->size -= 1;
    
        return item;
    }
    
    
    int main() {
        struct queue* myQueue = createQueue();
        struct queue_item_t item;
        item.exampleItemData = 665;
        queue(myQueue, item);
    
        item.exampleItemData = 666;
        queue(myQueue, item);
    
        item.exampleItemData = 667;
        queue(myQueue, item);
    
        for(int i = myQueue->size; i > 0; --i)
        {
            struct queue_item_t dequeuedItem = dequeue(myQueue);
            printf("Dequed ITem data = %i\n",  dequeuedItem.exampleItemData);
        }
    
        // Now the next shows an undefined state if someone dequeues with size 0 or smaller:
        struct queue_item_t dequeuedItem = dequeue(myQueue);
        printf("Dequed ITem data = %i\n",  dequeuedItem.exampleItemData);
    
        // I recommend using a boolean like mentioned above
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-23
      • 2016-04-06
      • 1970-01-01
      相关资源
      最近更新 更多