【问题标题】:Failed to free all used memory无法释放所有使用的内存
【发布时间】:2012-09-26 03:34:11
【问题描述】:

自动分级器告诉我我未能释放所有使用的内存。我不确定我在哪里导致了内存泄漏,所以这是我的整个代码:

struct lnode {
int count;
int line;
char* word;
struct lnode* next;
};


struct lnode* newNode(char* word, int line) {
struct lnode* temp = (struct lnode*)malloc(sizeof(struct lnode));
char* newWord = (char*)malloc(strlen(word) + 1);
newWord = strcpy(newWord, word);
temp->word = newWord;
temp->line = line;
temp->count = 1;
return temp;
}

void pushNode(struct lnode** head, struct lnode* node) {
node->next = *head;
*head = node;


}

struct lnode* getNode(struct lnode* head, char* word) {
struct lnode* current = head;
char* temp = (char *)malloc(strlen(word));
strcpy(temp, word);
while(current != NULL) {
    if(!strcmp(nodeGetWord(current),temp)) 
        return current; 

    current = nodeGetNext(current);
}
return NULL;
}

char* nodeGetWord(struct lnode* node) {
return node->word;
}

struct lnode* nodeGetNext(struct lnode* node) {
return node->next;
}

int nodeGetLine(struct lnode* node) {
int line = node->line;
return line;
}

int nodeGetCount(struct lnode* node) {
return node->count;
}

void nodeSetCount(struct lnode* node, int count) {
node->count = count;
}

void nodeSetLine(struct lnode* node, int line) {
node->line = line;
}

void deleteList(struct lnode** head) {
struct lnode* current = *head;
struct lnode* next;
while(current) {
    next = current->next;
    free(current);
    current = next;
}
*head = NULL;

}

void deleteNode(struct lnode** head, struct lnode* node) {
struct lnode* currentNode = *head;
struct lnode* previousNode = NULL;

while (currentNode != NULL) {
    if (currentNode != node) {
        previousNode = currentNode;
        currentNode = nodeGetNext(currentNode);
        continue;
    }

    if (previousNode)
        previousNode->next = node->next;
    else
        *head = node->next;
    free(node);
    break;
}
}

void printList(struct lnode** head) {
struct lnode* current = *head;
while (current != NULL) {
    printf("%s\n",nodeGetWord(current));
    current = nodeGetNext(current);
}

} 
int main() {
struct lnode* head = NULL;

struct lnode* a = newNode("Hello",3);
pushNode(&head, a);
struct lnode* b = newNode("Hi",2);
pushNode(&head, b);
struct lnode* c = newNode("Hola",4);
pushNode(&head, c);
struct lnode* d = newNode("Yo",5);
pushNode(&head, d);
struct lnode* e = newNode("Bye", 7);
pushNode(&head, e);
printList(&head);
//deleteNode(&head,e);
//printf("key: %s\n",nodeGetWord(e));
//printf("\n");
deleteList(&head);
printf("\n");
printList(&head);   
printf("\nDone\n");


}

可以忽略 main 和 printList() 函数,因为当我将其提交给自动评分器时,它们已被注释掉——它们仅用于测试目的。一切似乎对我来说都正常。我什至实现了一个全局整数,每当我malloc 某物时它就会更新,而每当有东西被释放时它就会递减。如果有人能指出可能的内存泄漏在哪里,那就太好了!

【问题讨论】:

  • 不要搜索。素描和思考。
  • 试着想象你是一台计算机,看看你是否能计算出当你试图删除列表的头部时你的 deleteNode() 函数会做什么。如果您的示例太繁琐而无法完成,请尝试一个更简单的模型,在该模型中将一个节点添加到列表中,然后从列表头中删除该节点。记下传递的参数和局部变量的初始值,并注意它们在您处理函数逻辑时如何变化。努力解决这个问题会给你解决方案,同时你自己解决这个问题而不是把答案交给你。
  • 在经历所有这些苦差事之前,最好先从概念上思考更高的层次。 OP 打印一个刚刚从列表中删除并释放的节点;这很明显是UB。 OP 有一些期望,即从列表中删除节点会影响打印节点......为什么?这是更改的列表;正如人们所期望的那样,打印列表会省略已删除的节点。
  • 为什么人们在没有解释的情况下投反对票?这个问题有什么问题? OP 提供了代码并解释了他的困惑......他还应该做什么?
  • 通过释放指针指向 free(ptr) 的东西,指针 ptr 仍然指向先前分配的现在释放的内存。如果您取消对指针的引用,它可能会或可能不会起作用,因为它是未定义的行为。

标签: c list linked-list


【解决方案1】:

您希望节点的 printf 做什么?为什么您期望从列表中删除某些内容会影响已删除内容的打印?

除了释放节点这一事实之外,从列表中删除节点并不相关......您正在打印节点,而不是列表。您正在打印的节点是您freed 的节点,这是未定义的行为。没有办法知道可能是什么行为。对于您的实现,它恰好打印了它在您 freed 之前的节点值,但您不能指望它或类似的东西。

编辑:

自动分级器告诉我,我未能释放所有使用的内存。

你为单词分配内存,但你从不释放它,你只释放节点。你应该用 freeNode 替换你的两个免费调用,并编写 freeNode 来释放节点拥有的任何内存,在本例中为 free(node->word) 和 free(node)。

【讨论】:

  • 我认为通过freeing 节点,如果我尝试访问结构的成员之一,它会吐出一个错误。
  • @MattAltepeter 什么是“它”? C 是一种低级语言,最初是为只有几 K(不是 M 或 G)内存的机器设计的;没有额外的运动部件,没有看门狗。如果您访问释放的内存,则所有赌注都将关闭。如果您从数组外部存储或读取,则所有赌注都将关闭。如果你想知道为什么有人会在这个时代教授或学习这样一种语言……我也是。
  • P.S.您应该考虑对已删除结构的任何字段的任何访问都会产生错误。怎么会被发现?请记住,计算机没有魔法……发生的一切,都是通过算法发生的。
  • @MattAltepeter P.P.S.你写了“它工作得很好,除非要删除的节点是头”......但如果你删除其他一些节点然后尝试打印它,它肯定不会吐出错误。您在删除头节点和删除其他节点时看到的不同行为是什么?你没说过。
  • @MattAltepeter 如果物理内存已与虚拟地址解耦并返回到操作系统,您只会得到段错误,但这只能按页完成,不能用于小分配,并且大多数mallocs 根本不这样做,因为它太昂贵(慢)。你的问题应该是关于来自自动评分器的消息:当你释放你的节点时,你不会释放它指向的字符串。现在你应该考虑接受我的回答。
【解决方案2】:

我猜nodeGetWord 只是从传递给它的节点中提取文本字符串,这就是为什么在删除节点后它仍然打印正确的字符串的原因。它根本不看列表。

但是,您确实有另一个更严重的错误,那就是您访问节点 e 您在 deleteNode 中释放它之后。这是未定义的行为,是一件坏事。

【讨论】:

    猜你喜欢
    • 2019-04-21
    • 1970-01-01
    • 2011-05-31
    • 2019-06-13
    • 1970-01-01
    • 2013-07-30
    相关资源
    最近更新 更多