Valgrind输出,缺少自由?

时间:2017-03-06 19:02:18

标签: c memory-leaks valgrind

所以,为学校做练习,但我们显然是在泄漏记忆。无论我多么盯着valgrind输出,我都无法弄明白。我想我们缺少3个免费?但它似乎也暗示我们的malloc存在问题,但唯一明确的malloc来自我们老师提供的代码。当然不是吗?也没有第299行,程序结束于239.但也许这是因为我在不同的PC上工作而不是运行valgrind的PC。

Valgrind输出的一部分:

ts

标题(已提供)

Invalid write of size 8
    at 0x.....: enqueue
    by 0x.....: insertUnique
    by 0x.....: timeable
    by 0x.....: main
Address 0x...... is 16 bytes inside a block of size 24 free'd
    at 0x.....: free (vg_replace_malloc.c:530)
    by 0x.....: removeFirstNode
    by 0x.....: dequeue
    by 0x.....: timeable
    by 0x.....: main
Block was alloc'd at
    at 0x.....: malloc (vg_replace_malloc.c:299)
    by 0x.....: addItem
    by 0x.....: enqueue
    by 0x.....: insertUnique
    by 0x.....: timeable
    by 0x.....: main

HEAP SUMMARY
in use at exit: 72 bytes in 3 blocks
total heap usage: 31 allocs, 28 frees, 2,744 bytes allocated

24 bytes in 1 blocks are definitely lost in loss records 2 of 3
    at 0x.....: malloc (vg_replace_malloc.c:299)
    by 0x.....: addItem
    by 0x.....: addItemAtPos
    by 0x.....: addItemAtPos
    by 0x.....: addItemAtPos
    by 0x.....: insertUnique
    by 0x.....: timeable
    by 0x.....: main

48 (24 direct, 24 indirect) bytes in 1 blovks are definitely lost in loss records 2 of 3
    at 0x.....: malloc (vg_replace_malloc.c:299)
    by 0x.....: addItem
    by 0x.....: enqueue
    by 0x.....: insertUnique
    by 0x.....: timeable
    by 0x.....: main

LEAK SUMMARY
definitely lost: 48 bytes in 2 blocks
indirectly lost: 24 bytes in 1 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 0 bytes in 0 blocks
suppressed: 0 bytes in 0 blocks

queues.c(已提供)

#ifndef QUEUES_H
#define QUEUES_H

/* First the type definitions. */

typedef struct State { /* a state contains a time and the states of the two sandglasses */
  int time;
  int sg1, sg2;
} State;

typedef struct ListNode *List;  /* List is the type of lists of states */

struct ListNode {
  State item;
  List next;
};


typedef struct Queue { /* a queue is a list and a pointer to the last node */
  List list;
  List lastNode;
} Queue;

List newEmptyList();
int isEmptyList (List li);
void listEmptyError();
List addItem(State s, List li);
void listTooShort();
List addItemAtPos(List li, State s, int p);
State firstItem(List li);
List removeFirstNode(List li);
void freeList(List li);
Queue newEmptyQueue ();
int isEmptyQueue (Queue q);
void emptyQueueError ();
void enqueue (State s, Queue *qp);
State dequeue(Queue *qp);
void freeQueue (Queue q);

 #endif

最后我们自己的代码(可能非常混乱,抱歉。在包含以前代码的地图中用-std = c99 -Wall * .c编译):

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "queues.h"

/* We use the functions on lists as defined in 1.3 of the lecture notes.
 */

List newEmptyList() {
  return NULL;
}

int isEmptyList (List li) {
  return ( li==NULL );
}

void listEmptyError() {    
  printf("list empty\n");
  abort();
}

List addItem(State s, List li) {
  List newList = malloc(sizeof(struct ListNode));
  assert(newList!=NULL);
  newList->item = s;
  newList->next = li;
  return newList;
//  free(newList); maybe?
}

void listTooShort(){
    printf("List too short\n");
    abort();
}

List addItemAtPos(List li, State s, int p){
    if (p ==0){
        return addItem(s,li);
    }
    if (li == NULL){
        listTooShort();
        //addItem(s, li);
    }
    li->next =addItemAtPos(li->next, s, p-1);
    return li;
}


State firstItem(List li) {
  if ( li == NULL ) {
    listEmptyError();
  }
  return li->item;
}

List removeFirstNode(List li) {
  List returnList;
  if ( li == NULL ) {
    listEmptyError();
  }
  returnList = li->next;
  free(li);
  return returnList;
}

void freeList(List li) {
  List li1;
  while ( li != NULL ) {
    li1 = li->next;
    free(li);
    li = li1;
  }
  return;
}


/* We define some functions on queues, based on the definitions in 1.3.1 of the
 * lecture notes. Integers are replaced by states, and enqueue has output type void here.
 */

Queue newEmptyQueue () {
  Queue q;
  q.list = newEmptyList();
  q.lastNode = NULL;
  return q;
}

int isEmptyQueue (Queue q) {
  return isEmptyList(q.list);
}

void emptyQueueError () {
  printf("queue empty\n");
  exit(0);
}

void enqueue (State s, Queue *qp) {
  if ( isEmptyList(qp->list) ) {
    qp->list = addItem(s,NULL);
    qp->lastNode = qp->list;
  } else {
    (qp->lastNode)->next = addItem(s,NULL);
    qp->lastNode = (qp->lastNode->next);
  }
}

State dequeue(Queue *qp) {
  State s = firstItem(qp->list);
  qp->list = removeFirstNode(qp->list);
  if ( isEmptyList(qp->list) )  {
    qp->lastNode = NULL;
  }
  return s;
}

void freeQueue (Queue q) {
    freeList(q.list);
}

如果你能帮助我发现这个问题,我将非常感激,我们在这方面有点不高兴。或者解释一下valgrind消息实际意味着什么?我见过的大多数帖子似乎都出现了malloc的错误(例如,使用sizeof(int)作为指针),但据我所知,这并非如此。什么是直接和间接损失之间的差异?无论如何,是否有一个非常低效的部分?较大的值需要很长时间(例如11 39 10000)。

2 个答案:

答案 0 :(得分:0)

  

或者也许解释一下valgrind消息实际意味着什么?

Valgrind good documentation涵盖了这一点以及更多内容。简而言之:

&#34;无效写&#34;消息表示您已尝试写入当前未分配给您的程序的内存。在你的特殊情况下,valgrind抱怨你在被释放后写入一块内存。

A&#34;块肯定会丢失&#34;消息表示您有内存泄漏。在程序结束时,分配的内存不可能通过任何指针链到达。一个块直接&#34;直接&#34;如果没有指向该区块的指针,则会丢失。一个区块是间接的&#34;如果仍有指针丢失,但所有这些都存在于无法到达的区块中。

在任何一种情况下,您特定丢失记录中报告的行号都是指Valgrind自己实现的文件,您可以从提供的文件名中看出。

然而,所有这一切似乎都没有实际意义,因为我无法通过您提供的代码和输入重现我环境中的内存问题,而且我没有理由认为我应该能够要做。

  

无论如何,是否存在效率极低的部分?

您的算法会探索系统状态空间的整个区域,其中经过的时间不会超过目标时间。我认为这是意图。但是,您要搜索O(cap1 * cap2 * goalTime)个状态,并且为了避免冗余计算,您在添加每个状态时搜索队列的内容。这似乎是成本最高的一步,导致O的总体界限(cap1 2 * cap2 2 * goalTime 2 )。当然,这只是一个上限,可以有比上限快得多的输入。

另一方面,是的,有一些严重的低效率。特别是,insertUnique()所做的工作量大约是它需要做的工作量的两倍,因为它遍历列表以找到插入位置(findPos()),然后再次遍历它 执行实际插入(addItemAtPos())。可能会有一些其他的小效率,但没有相同的范围。

此外,您通过使用队列使事情变得比他们需要的更复杂,因为您没有将用作队列。您将使用队列实现的内部列表作为列表。这提出了两种问题:

  • 如果练习要求您使用队列执行任务,那么您的方法不会得到我的满分,因为您主要依赖于列表操作,而不是队列操作。可以使用队列操作执行重复数据删除,但它需要两个队列。

  • 如果练习允许您使用列表而不是队列,那么您的方法仍然将无法获得我的满分(尽管它会比其他情况更好) ,因为我不清楚你是否真的明白你是在使用列表而不是队列。

另请注意:练习的结构,尤其是您正在努力解决的低效问题,似乎是引入新数据结构的理想方法:优先级队列。对于这个问题,这比普通队列更好。

答案 1 :(得分:0)

在开始调查任何泄漏之前,您需要解决第一个错误(“无效写入大小8”)。此诊断是错误 - 它表示您的程序正在尝试写入已释放的内存。这实际上可能是后来报告的一些泄漏的原因。

Valgrind输出中提到的唯一行号是相对于vg_replace_malloc.c。这个文件是Valgrind的内部文件;重要的是它上面的堆栈帧。要在代码中获取行号,您需要使用调试符号编译代码 - 添加-ggdb编译器选项并重新构建应用程序。