代码之家  ›  专栏  ›  技术社区  ›  GabrielChu

如何释放带有指针的链表

  •  1
  • GabrielChu  · 技术社区  · 7 年前

    我试图以迭代方式释放链接列表的内存。这个列表有一个类似这样的结构,在这个链表中,如果它在这个列表中,我不会添加url。

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

    一旦使用完这个链表,我试图释放它,但出现了分段错误,我仍在学习中 c ,除了直接搜索相关主题外,我对如何调试此类错误没有太多线索。引用了一些SOs this one ,则, this one this one ,仍然无法确定它是在哪里坠毁的。

    这是我的密码。如果您认为我在这个实现中遗漏了什么,可以随意添加评论。

    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。

    2 回复  |  直到 7 年前
        1
  •  2
  •   John3136    7 年前

    head->url = "/";

    这不是malloced数据,所以您无法释放它!

    你的另一个问题是 url_push() 具有 new_node->url = malloc(url_size); 它没有为字符串中的终止0分配足够的空间(也没有复制终止0,因此您最终不会“踩踏内存”,但确实有未终止的字符串…)。尝试 new_node->url = strdup(url); 相反

    按样式:计算 url_size 在里面 url\u推送() 而不是每次打电话 strlen() 在被调用的函数中执行一次(注意如果使用 strdup() 那么你不需要 url\u大小 完全

    最后一点:像valgrind这样的工具很容易发现这两个问题。

        2
  •  1
  •   chqrlie    7 年前

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

    • 您没有为 new_node->url 字符串输入 url_push ,导致 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;
    }