为什么Valgrind在错误的地方给我错误?

时间:2016-10-28 02:31:18

标签: c debugging memory-management valgrind

我在以下C程序中修复了三个错误。前两个给出并保证是正确的。第三个是我将在最后写的一个,与我的问题无关。最后三个问题出在哪里,每个都出现错误。

这是我的计划:

/* is correct*/
Node *create_list(int arr[], int size) {
  Node *n, *list= NULL;

  if (arr != NULL && size != 0)
    while (size-- > 0) {

      n= malloc(sizeof(*n));
      if (n == NULL)
        return NULL;  /* we just return NULL if memory allocation fails */
      else {
        n->value= arr[size];
        n->next= list;
        list= n;
      }
    }

  return list;
}

/* is correct*/
void list_to_string(Node *list, char result[]) {
  char temp[MAX_LEN + 1];

  strcpy(result, "");  /* clear out any existing contents */

  while (list != NULL) {
    sprintf(temp, "%d", list->value);

    if (strlen(result) + strlen(temp) + 1 < MAX_LEN) {
      strcat(result, temp);

      /* add a space if it's not the last element */
      if (list->next != NULL)
        strcat(result, " ");
    }

    list= list->next;
  }
}

/*****************************************************************************/
/*       functions below this have something wrong with them     */
/*****************************************************************************/

/* this function's parameter is a pointer to the head node of a list; it
 * should release all of the memory of the list, and set the head pointer
 * (meaning the pointer that its parameter points to) to NULL. (Empty for now).
 */
void clear(Node **list) {
}

/* should return the sum of the values in the even-numbered positions of a
 * list (the value in the second node, the fourth node, etc.), but has a bug
 * (the first node is considered to be position #1, in other words, the list
 * has no position zero)
 */
int sum_even(Node *list) {
  Node *ptr= list->next;
  int sum= 0;

  if (list != NULL){
    while (ptr != NULL) {
      sum += ptr->value;
      ptr= ptr->next->next;
    }  
  }

  return sum;
}

/* should remove the last element from a list, returning 1 upon success or 0
 * if start is NULL, but has a bug
 */
int remove_last(Node **start) {
  Node *prev= NULL, *travel;
  int result= 0;

  if (start != NULL) {

    result= 1;

    travel= *start;
    while (travel != NULL && travel->next != NULL) {
      prev= travel;
      travel= travel->next;
    }

    if (prev != NULL) {
      free(prev->next);
      prev->next= NULL;
    }

  }

  return result;
}

/* should remove the first element from a list, returning 1 upon success or
 * 0 if the list is empty or start is NULL, but has a bug
 */
int remove_first(Node **start) {
  Node **temp= NULL;
  int result= 0;

  if (start != NULL && *start != NULL) {

    result= 1;
    temp= start;
    *start= (*start)->next;
    free(temp);

  }

  return result;
}

我的主要测试功能:

int main(void) {
  int arr[]= {10, 20, 30, 40, 50, 60, 70};
  Node *list= NULL;
  char elements[MAX_LEN + 1];

  list= create_list(arr, sizeof(arr) / sizeof(arr[0]));

  /* test sum_even() */
  assert(sum_even(list) == 120);

  /* test remove_last() */
  remove_last(&list);
  list_to_string(list, elements);
  assert(strcmp(elements, "10 20 30 40 50 60") == 0);

  printf("Score!\n");  /* both assertions passed */

  /* if your clear() function works, this program should not have any memory
     leaks, and list should be NULL afterwards */
  clear(&list);

  return 0;
}

我理解&#39; clear()&#39;是空的,但这是我将在最后写的一个函数。当我用valgrind运行时,我感到困惑的是:

valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --track-fds=yes my_program.x

我收到此消息:

==25457== Memcheck, a memory error detector
==25457== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==25457== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==25457== Command: public1.x
==25457==
Score!
==25457==
==25457== FILE DESCRIPTORS: 3 open at exit.
==25457== Open file descriptor 2: /dev/pts/11
==25457==    <inherited from parent>
==25457==
==25457== Open file descriptor 1: /dev/pts/11
==25457==    <inherited from parent>
==25457==
==25457== Open file descriptor 0: /dev/pts/11
==25457==    <inherited from parent>
==25457==
==25457==
==25457== HEAP SUMMARY:
==25457==     in use at exit: 96 bytes in 6 blocks
==25457==   total heap usage: 7 allocs, 1 frees, 112 bytes allocated
==25457==
==25457== 80 bytes in 5 blocks are indirectly lost in loss record 1 of 2
==25457==    at 0x4C28A2E: malloc (vg_replace_malloc.c:270)
==25457==    by 0x40077F: create_list (broken-lists.c:16)
==25457==    by 0x400698: main (public1.c:14)
==25457==
==25457== 96 (16 direct, 80 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==25457==    at 0x4C28A2E: malloc (vg_replace_malloc.c:270)
==25457==    by 0x40077F: create_list (broken-lists.c:16)
==25457==    by 0x400698: main (public1.c:14)
==25457==
==25457== LEAK SUMMARY:
==25457==    definitely lost: 16 bytes in 1 blocks
==25457==    indirectly lost: 80 bytes in 5 blocks
==25457==      possibly lost: 0 bytes in 0 blocks
==25457==    still reachable: 0 bytes in 0 blocks
==25457==         suppressed: 0 bytes in 0 blocks
==25457==
==25457== For counts of detected and suppressed errors, rerun with: -v
==25457== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)

这清楚地表明对create_list()的函数调用存在问题。既然我知道create_list()是正确的并且remove_last()有问题,为什么它告诉我create_list()有问题?

我现在正试图学习Valgrind所以请原谅我这个问题对你们有些人是否明显。

2 个答案:

答案 0 :(得分:0)

create_list在循环内调用malloc。如果循环中的malloc在前N次正常但是在N + 1时间内失败,则返回NULL,从而从前N个malloc泄漏内存。所以这显然是create_list中的一个错误,我希望valgrind报告错误。

您需要以下内容:

if (n == NULL)
{
    clear(&list);
    return NULL;  /* we just return NULL if memory allocation fails */
}

除此之外,我不确定在实施valgrind功能之前运行clear是否有意义。 valgrind应该如何知道你打算在尚未编写的函数中释放内存?

答案 1 :(得分:0)

我发现了问题所在。 事实证明,clear()需要在main存在之前被调用,或者list将包含不同的内存。 由于这三个功能存在缺陷,我一开始并不认为这是个案。 sum_even()和remove_last()中的错误不适用于main()中的特定列表。所以对于这次运行,没有错。