【问题标题】:How to free a linked list with pointers如何释放带有指针的链表
【发布时间】:2018-09-29 07:33:53
【问题描述】:

我试图迭代地为链表释放内存。该列表有一个看起来像这样的结构,在这个链表中,如果它在这个列表中,我不会添加一个 url。

struct Node {
    char *url;
    struct Node *next;
};

处理完这个链表后,我尝试释放它,但出现分段错误,我仍在学习c,除了如何调试此类错误之外,我没有太多线索直接搜索相关主题。引用了一些 SO this onethis onethis one,仍然无法确定它在哪里崩溃。

这是我的代码。如果您认为我在此实现中遗漏了什么,请随意添加 cmets。

void url_push(struct Node *head, const char *url, size_t url_size) {
    struct Node *new_node = (struct Node *) malloc(sizeof(struct Node));

    new_node->url = malloc(url_size);
    new_node->next = NULL;

    for (int i = 0; i < url_size; i++)
        *(new_node->url + i) = *(url + i);

    struct Node *current = head;
    while(1) {
        if (strcmp(current->url, new_node->url) == 0) {
            printf("Seen page %s!!!!!\n", new_node->url);
            free(new_node);
            break;
        } else if (current->next == NULL) {

            current->next = new_node;
            break;
        } else {
            current = current->next;
        }
    }
}

int main() {
    struct Node *head = (struct Node*)malloc(sizeof(struct Node));
    head->url = "/";
    head->next = NULL;

    char *url = "www.google.com";
    url_push(head, url, strlen(url));

    url = "www.yahoo.com";
    url_push(head, url, strlen(url));

    url = "www.google.com";
    url_push(head, url, strlen(url));

    url = "www.wsj.com";
    url_push(head, url, strlen(url));

    struct Node *current = NULL;

    while ((current = head) != NULL) {
        printf("url: %s\n", head->url);

        head = head->next;
        free(current->url);
        free(current);
    }
}

已编辑: 为了减少混淆,我修改了结构。使用strcmp的目的是避免添加已经看到的url。

【问题讨论】:

  • 你需要一个remove() 方法来实现删除列表中单个节点的逻辑。这必须注意将前一个节点重新连接到列表中的下一个节点。
  • 回答你的问题有太多错误。 invalid、redirect 和 page_size 变量是如何设置的?如果你从不移动它,当前指针是什么?头不应该移动,因为它是列表的开始。既然可以结束程序,为什么还要释放列表?
  • 您编辑了结构,但现在您的代码无法编译。如果您提供的代码与您正在使用的代码不同(您通常应该这样做),请确保它重现了相同的问题。
  • here,看看一个好的实现示例 ;) 就像 linus 说“不要说话,给我看代码”

标签: c pointers linked-list


【解决方案1】:

您的代码中存在多个问题:

  • 您没有为url_push 中的new_node-&gt;url 字符串的空终止符分配空间,导致strcmp() 也有未定义的行为。
  • 第一个节点未正确构造:未分配其url 指针。
  • 你不检查内存分配失败

您应该使url_push() 更通用:它应该通过返回新的head 指针来处理空列表。不需要传递url 字符串的长度,使用strdup() 即可,并且在检查重复之前应避免分配新节点。

这是修改后的版本:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Node {
    char *url;
    struct Node *next;
};

struct Node *url_push(struct Node *head, const char *url) {

    struct Node *current = head;
    if (current != NULL) {
        for (;;) {
            if (strcmp(current->url, url) == 0) {
                printf("Seen page %s before!!!!!\n", url);
                return head;
            } else if (current->next == NULL) {
                break;
            } else {
                current = current->next;
            }
        }
    }
    struct Node *new_node = malloc(sizeof(struct Node));

    if (new_node == NULL || (new_node->url = strdup(url)) == NULL) {
        fprintf(stderr, "memory allocation failure\n");
        exit(1);
    }
    new_node->next = NULL;

    if (current == NULL) {
        head = new_node;
    } else {
        current->next = new_node;
    }
    return head;
}

int main() {
    struct Node *head = NULL;

    head = url_push(head, "/");
    head = url_push(head, "www.google.com");
    head = url_push(head, "www.yahoo.com");
    head = url_push(head, "www.google.com");
    head = url_push(head, "www.wsj.com");

    while (head != NULL) {
        printf("url: %s\n", head->url);
        struct Node *current = head;
        head = head->next;
        free(current->url);
        free(current);
    }
    return 0;
}

【讨论】:

  • 我只是想知道 char *url = "www.google.com" 是否有终止 0?如果有,为什么我们不能使用 strcpy?如果它没有,我们是否也将 0 添加到 url 中?
  • @GabrielChu:字符串文字当然有一个空终止符。如果您分配了正确的大小,您可以使用strcpystrlen(url) + 1,但您可以使用同时进行分配和复制的 Posix 规范化函数 strdup()
【解决方案2】:

head-&gt;url = "/";

这不是分配的数据,所以你不能释放它!

您的另一个问题是在url_push()new_node-&gt;url = malloc(url_size); 中,它没有为字符串中的终止 0 分配足够的空间(也没有复制终止的 0,因此您最终不会“踩到内存”但确实有未终止的字符串...)。请改用new_node-&gt;url = strdup(url);

风格明智:在 url_push() 中计算 url_size 而不是让每个调用者调用 strlen() 在被调用的函数内执行一次(请注意,如果您使用 strdup(),那么您不需要 url_size at全部。

最后说明:像 valgrind 这样的工具可以轻松发现这两个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-22
    • 1970-01-01
    相关资源
    最近更新 更多