双重释放或损坏 - 删除列表的第一个节点时出错

时间:2015-05-22 18:28:11

标签: c list struct nodes

我有以下代码从列表中删除元素。当结构的一个元素低于我使用它的值时,我必须删除该节点。

代码如下:

void DeleteNode(frota** head, int MAX, int nSquareW){
    int i, eliminate = 0;
    frota* curr = *head;
    frota* curr1 = curr;
    if(*head != NULL)
    {
        while(curr1 != NULL)
        {
            if(curr1->bateria < MAX)
            {
                if( *head == curr1){
                    if(curr1->next != NULL){
                        (curr1->next)->prev = NULL;
                    }
                    *head = curr1->next;
                }else if(curr1 -> next == NULL){
                    (curr1->prev)->next = NULL;
                }else{
                    (curr1->next)->prev = curr1->prev;
                    (curr1->prev)->next = curr1->next;
                } 
                eliminate = 1;
             }
             curr1 = curr1->next;
             if(eliminate == 1){
                 eliminate = 0;
                 printf("entrei1");
                 for(i=0;i<nSquareW;i++){
                     free(curr->percorridos[i]);
                 }
                 free(curr->percorridos);
                 free(curr);
             }
             curr = curr1;   
         }
    }
}

当我尝试删除最后和中间节点时代码运行良好(值头等于第一个节点,除非没有,然后值为NULL),但是当我尝试删除第一个节点时,我得到以下错误:

*** Error in './iClean': double free or corruption (!prev): 0x09bd4a20 ***

有人已经告诉我问题在于删除节点(free())并且我无法做任何事情。

任何帮助都会受到赞赏。

修改

nSquareWidth是地图的宽度。

这是生成percorridos的代码:

void faz_mapa(matriz *** mapa, int nSquareW, int nSquareH){

    *mapa = malloc(nSquareW * sizeof(matriz*));
    for (int i = 0; i < nSquareW; i++)
    {
        (*mapa)[i]= malloc( nSquareH * sizeof(matriz));
    }

    for (int i = 0; i < nSquareW; i++)
    {
        for (int j = 0; j < nSquareH; j++)
        {

        //inicializa divisao suja
        (*mapa)[i][j].limpo = 0;
        (*mapa)[i][j].ocupado = NULL;
        }   
    }

}

结构:

typedef struct robot {
   int bateria;
   char nome[STRING_SIZE];
   int pos_x;
   int pos_y;
   int target_x;
   int target_y;
   int limpos;
   matriz ** percorridos;
   struct robot * next;
   struct robot * prev;
}frota;

2 个答案:

答案 0 :(得分:0)

我没有运行你的代码,但显然只有一个地方我们可以遇到双重免费。

for(i=0;i<nSquareW;i++){
  free(curr->percorridos[i]);
}

free(curr->percorridos);
free(curr);

您是否有curr->percorridoscurr相同的情况,或者curr->percorridos[i]curr->percorridos相同?

你可以通过在每次免费电话会议之前添加一个print语句来找到它。然后找出哪两个被调用。

for(i=0;i<nSquareW;i++){
  printf("Freeing curr->perrcorridos[i] at %p\n", curr->percorridos[i]);
  free(curr->percorridos[i]);
}

printf("Freeing curr->perrcorridos at %p\n", curr->percorridos);
free(curr->percorridos);

printf("Freeing curr at %p\n", curr);
free(curr);

答案 1 :(得分:0)

由于双链表编程问题经常出现在Stack Overflow上,我的答案将展示如何以一种非常安全的方式进行双链表。它使用顶级列表类型定义和标记条目。仍然有一些空间,但代码很容易测试和调试,因为不同的方面由各个函数在本地处理。

原始问题中的delete()函数存在以下问题:它负责两个不同的事情:1。处理双链表删除内容2.做一些特定于应用程序的过滤。

我的代码还显示,在这样的列表上运行的应用程序代码可以与列表管理代码分开。

#include <stdint.h>
#include <stdlib.h>
typedef struct NodeType_tag { int32_t value; NodeType_tag *Next; NodeType_tag *Prev; } NodeType;
typedef struct { NodeType sentinel; NodeType *head; NodeType *tail; } NodeList;

void NodeListInit(NodeList * nodeList)
{
    nodeList->sentinel.Next = &nodeList->sentinel;
    nodeList->sentinel.Prev = &nodeList->sentinel;
    nodeList->head = &nodeList->sentinel; 
    nodeList->tail = &nodeList->sentinel;
}
int NodeListIsEmpty(NodeList * nodeList)
{
    return nodeList->head == &nodeList->sentinel;
}
void NodeListAddFront(NodeList* nodeList, uintptr_t value)
{
    NodeType *newNode = (NodeType*)malloc(sizeof(NodeType));
    if (NULL != newNode)
    {
        newNode->value = value;

        newNode->Prev = nodeList->head->Prev;
        newNode->Next = nodeList->head;
        nodeList->head->Prev = newNode;
        nodeList->head = newNode;
        if (nodeList->tail == &nodeList->sentinel)
            nodeList->tail = newNode;
    }
}
void NodeListAddBack(NodeList* nodeList, int32_t value)
{
    NodeType *newNode = (NodeType*)malloc(sizeof(NodeType));
    if (newNode != NULL)
    {
        newNode->value = value;
        newNode->Prev = nodeList->tail;
        newNode->Next = nodeList->tail->Next;
        nodeList->tail->Next = newNode;
        nodeList->tail = newNode;
        if (nodeList->head == &nodeList->sentinel)
            nodeList->head = newNode;
    }
}

NodeType *NodeListHead(NodeList*nodeList)
{
    if (&nodeList->sentinel != nodeList->head)
        return nodeList->head;
    return NULL;
}

NodeType *NodeListTail(NodeList* nodeList)
{
    if (&nodeList->sentinel != nodeList->tail)
        return nodeList->tail;
    return NULL;
}

NodeType *NodeListNext(NodeList * nodeList, NodeType * current)
{
    if (NULL != current)
    {
        if (current->Next != &nodeList->sentinel)
            return current->Next;
    }
    return NULL;
}

NodeType *NodeListPrev(NodeList *nodeList, NodeType *current)
{
    if (NULL != current)
    {
        if (current->Prev != &nodeList->sentinel)
            return current->Prev;
    }
    return NULL;
}

NodeType* NodeListRemoveForward(NodeList* nodeList, NodeType *target)
{
    NodeType* next = NULL;
    if (target != NULL)
    {
        target->Prev->Next = target->Next;
        target->Next->Prev = target->Prev;
        if (target == nodeList->head)
            nodeList->head = target->Next;
        if (target == nodeList->tail)
            nodeList->tail = target->Prev;
        if (&nodeList->sentinel != target->Next)
            next = target->Next;
        free(target);
    }
    return next;
}
// return 1 if value passes filter. 
// return 0 if value is not passing filter.
typedef int(*FilterFunction_t)(int32_t value);

size_t NodeListFilter(NodeList *nodeList, FilterFunction_t filter)
{
    NodeType * current = NodeListHead(nodeList);
    size_t removeCount = 0;
    while (current != NULL)
    {
        if (filter(current->value))
        {
            // passed filter -> keep it.
            current = NodeListNext(nodeList, current);
        }
        else
        {
            // did not pass filter - kill it!
            current = NodeListRemoveForward(nodeList, current);
            removeCount++;
        }
    }
    return removeCount;
}

void NodeListClear(NodeList *nodeList)
{
    NodeType *current = NodeListHead(nodeList);
    while (current != NULL)
    {
        current = NodeListRemoveForward(nodeList, current);
    }
}

void DumpNodeList(NodeList* nodeList)
{
    NodeType * current = NodeListHead(nodeList);
    size_t i;
    for (i = 0; current != NULL; i++, current = NodeListNext(nodeList,current))
    {
        printf("%d: %d\n", i, current->value);
    }
}

int FilterAllOddValues(int32_t value)
{
    if (0 == value % 2)
        return 1;
    return 0;
}
void TestNodeList()
{
    NodeList myNodeList;
    NodeListInit(&myNodeList);
    for (int32_t value = 0; value < 10; value++)
    {
        NodeListAddBack(&myNodeList, value);
    }
    DumpNodeList(&myNodeList);
    size_t removeCount = NodeListFilter(&myNodeList, FilterAllOddValues);
    printf("%d nodes removed by filter.\n", removeCount);
    DumpNodeList(&myNodeList);
    NodeListClear(&myNodeList);
}

一个显而易见的方面是,与非哨兵实施相比,头/尾特殊处理if-branches的数量大大减少。

另一个显而易见的方面是我使用c ++编译器运行它,因此在malloc()语句中添加了一个强制转换。请拒绝写出评论的冲动,例如“Do not cast malloc()”,所有你的核心c程序员;)

我使用下面给出的测试代码进行了简短的冒烟测试。测试代码未涵盖的功能可能仍有错误。