所以,为学校做练习,但我们显然是在泄漏记忆。无论我多么盯着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)。
答案 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
编译器选项并重新构建应用程序。