链表中的C内存泄漏

时间:2014-09-18 04:52:20

标签: c linux valgrind

我正在试图在c中创建一个链接列表,其中包含遵循此结构的各种节点:

typedef struct sll_node
{
  char label[LABEL_SIZE];
  int value;
  struct sll_node* next;
}sll_node;

我的输出是我运行代码的每个测试的预期输出,但是当在valgrind下运行时,我收到内存泄漏错误;

==8001== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1
==8001==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8001==    by 0x4012B8: make_node (slist.c:53)
==8001==    by 0x401337: sll_add (slist.c:91)
==8001==    by 0x40108B: test_stress1 (sample-driver.c:188)
==8001==    by 0x401277: main (sample-driver.c:258)

我已经检查了将新节点添加到列表中的所有代码,但我认为那里没有错误

sll_node *sll_add(sll_node *list, int value, const char *label)
{
  sll_node *NewNode = make_node(value, label);
  sll_node *ListNode = list;

  if(list == 0)
    return NewNode;

  while(ListNode->next != 0)
  {
    ListNode = ListNode->next;
  }

  ListNode->next = NewNode;

  return list;
}

所以我认为剩下的唯一错误是在从列表中删除节点的函数中。

该函数应该在所有节点中搜索具有应该擦除的值的节点,并且如果由于此操作而改变了头节点,则将新的开头返回到列表中,以防它找不到它应该只返回列表指针的搜索值:

sll_node *sll_remove(sll_node *list, int search_value)
{
  sll_node *IwillDeleteThis = list;
  sll_node *ThisIsBeforeWhatIWillDelete = 0;


  if(list == 0)
    return 0;

  if(list->value == search_value)
  {
    if(list->next)
    {
      sll_node *NewBeginning = list->next;
      free(list);
      return NewBeginning;
    }
    free(list);
    return 0;
  }


  while(IwillDeleteThis)
  {
    if(IwillDeleteThis->value == search_value)
    {
      ThisIsBeforeWhatIWillDelete->next = IwillDeleteThis->next;
      free(IwillDeleteThis);
      return list;
    }
    ThisIsBeforeWhatIWillDelete = IwillDeleteThis;
    IwillDeleteThis = IwillDeleteThis->next;
  }

  return list;
}

我认为,在评估我必须删除的列表的可能性时,我可能会感到很沮丧,但我不知道它是什么情况。

如果你指出我错在哪里,那将是非常有帮助的。

谢谢。

修改

以防万一,这是我用来测试代码的代码:

#define VERBOSEx
void test_stress1(void)
{
  #define SIZE 4500
  sll_node *list = NULL;
  int i, count = 0;
  int *a = malloc(2 * SIZE * sizeof(int));
  char buf[LABEL_SIZE];

  for (i = 0; i < SIZE; i++)
  {
    a[count++] = i + 1;
    sprintf(buf, "%08i", a[i]);
    list = sll_add(list, a[i], buf);  
  }
  #ifdef VERBOSE
  sll_dump(list);
  #endif

  for (i = 0; i < SIZE; i++)
  {
    int r1 = RandomInt(0, 1);
    int r2 = RandomInt(1, count);
    a[count] = count + 1;
    count++;
    sprintf(buf, "%08i", count);

    if (r1)
      list = sll_insert_before(list, r2, count, buf);
    else
      sll_insert_after(list, r2, count, buf);

    #ifdef VERBOSE
    sll_dump(list);
    printf("%s %i", r1 ? "before" : "after", r2);
    #endif
  }
  #ifdef VERBOSE
  sll_dump(list);
  #endif

  /*PrintArray(a, count);*/
  Shuffle(a, count);
  /*PrintArray(a, count);*/

  for (i = 0; i < 2 * SIZE - 20; i++)
  {
    list = sll_remove(list, a[i]);
    #ifdef VERBOSE
    sll_dump(list);
    #endif
  }

  sll_dump(list);
  sll_destroy(list);

  free(a);
}

EDIT2:

这是破坏列表的代码:

void sll_destroy(sll_node *list)
{
  sll_node *NodeToDelete = list;
  if(list == 0)
    return;  

  while(NodeToDelete)
  { 
    sll_node *DeleteNow = NodeToDelete;
    NodeToDelete = NodeToDelete->next;
    free(DeleteNow);
  }
}

EDIT3: 我用来将节点添加到列表中的一些额外函数

sll_node *sll_insert_before(sll_node *list, int search_value, int value, const char *label)
{
  sll_node *NewNode = make_node(value, label);
  sll_node *NodeToChangePosWith = list;
  sll_node *PreviousNode = list;

  if(list->value != search_value)
  {
    while(NodeToChangePosWith != 0 &&
          NodeToChangePosWith->value != search_value)
    {
      PreviousNode = NodeToChangePosWith;
      NodeToChangePosWith = NodeToChangePosWith->next;
    }
  }
  else 
  {
    NewNode->next = list;
    return NewNode;
  }

  if(NodeToChangePosWith == 0)
  {
    free(NewNode);
    return list;
  }
  PreviousNode->next = NewNode;
  NewNode->next = NodeToChangePosWith;
  if(PreviousNode == list)
  {
    return NewNode;
  }

  return list;
}


void sll_insert_after(sll_node *list, int search_value, int value, const char *label)
{
  sll_node *NewNode = make_node(value, label);
  sll_node *NodeToChangePosWith = list;

  while(NodeToChangePosWith->next != 0 &&
        NodeToChangePosWith->value != search_value)
  {
    NodeToChangePosWith = NodeToChangePosWith->next;
  }
  if(NodeToChangePosWith->next == 0 &&
     NodeToChangePosWith->value != search_value)
  {
    free(NewNode);
    return;
  }

  NewNode->next = NodeToChangePosWith->next;
  NodeToChangePosWith->next = NewNode;

}

2 个答案:

答案 0 :(得分:1)

您在此处复制的源代码太多;但为了找到错误,我建议你做以下事情:

1-使用Valgrind的Massif heap profiler

2-使用Massif visualizer查看内存的分配和释放位置(此工具可视化最后一步的输出。

3-另外,为了查看程序执行期间调用的函数,我建议您使用Valgrind's CallgrindKCachegrind来显示它的输出。

答案 1 :(得分:1)

当您在列表的第二个元素之前插入时,错误位于sll_insert_before。在这种情况下,在while循环之后,PreviousNode将指向第一个元素,NodeToChangePosWith将指向第二个元素。您在NewNodePreviousNode之间插入了NodeToChangePosWith,但是您有一个不必要的(并且不正确的)测试,看看PreviousNode是否等于list(它是在这种情况下),并返回NewNode作为新的第一个元素,它泄漏了真正的第一个元素。

顺便说一下,以下代码消除了所有特殊情况:

sll_node *sll_add(sll_node *list, int value, const char *label)
{
    sll_node *newNode = make_node(value, label);
    sll_node **nextPtr = &list;

    while(*nextPtr != 0)
    {
        nextPtr = &(*nextPtr)->next;
    }

    *nextPtr = newNode;

    return list;
}

sll_node *sll_remove(sll_node *list, int search_value)
{
    sll_node **nextPtr;
    sll_node *node;

    for(nextPtr = &list; (node = *nextPtr) != 0; nextPtr = &node->next)
    {
        if(node->value == search_value)
        {
            *nextPtr = node->next;
            free(node);
            break;
        }
    }

    return list;
}

void sll_destroy(sll_node *list)
{
    while(list != 0)
    {
        sll_node *nodeToDelete = list;
        list = list->next;
        free(nodeToDelete);
    }
}

sll_node *sll_insert_before(sll_node *list, int search_value, int value, const char *label)
{
    sll_node **nextPtr;
    sll_node *node;

    for(nextPtr = &list; (node = *nextPtr) != 0; nextPtr = &node->next)
    {
        if(node->value == search_value)
        {
            sll_node *newNode = make_node(value, label);
            newNode->next = node;
            *nextPtr = newNode;
            break;
        }
    }

    return list;
}

void sll_insert_after(sll_node *list, int search_value, int value, const char *label)
{
    while(list != 0)
    {
        if(list->value == search_value)
        {
          sll_node *newNode = make_node(value, label);
          newNode->next = list->next;
          list->next = newNode;
          break;
        }
    }
}