【问题标题】:Attempting to free() a linked list node causes segmentation fault in C尝试释放()链表节点会导致 C 中的分段错误
【发布时间】:2013-10-02 15:13:11
【问题描述】:

我想我的问题很简单。是的,我知道堆栈溢出有几个与链表/分段错误相关的问题,但我认为这些问题与未初始化的指针有关,而我认为我的问题与字符串有关。

我有一个链表,其节点结构由两个变量组成:指向next 节点的链接和(!)string

我的问题:我如何释放节点的内存(记住它是mallocated)而不会因free()ing 字符串而导致分段错误?

在浏览与free()strings 相关的其他问题时,我的印象是没有必要free() 他们。但是如何释放其中包含string 嵌套字符串的struct

除了destroyList() 之外,我正在实现的链表函数似乎都在工作,它释放了传递给函数的节点的所有已分配内存以及所有后续节点。

下面是实现:

void destroyList(struct listNode *pNode){
    if(pNode->next != null){
        destroyList(pNode->next);
    }
    free(pNode);
}

这是listNode 结构:

struct listNode{
    char addr[MAX_ADDR_LENGTH];
    struct listNode *next;
};

【问题讨论】:

  • 是否有可能在某个时候将超过 MAX_ADDR_LENGTH 的字符写入节点?可能是错误的,但这可能会弄乱你的指针。另外,您是否在创建时将其初始化为 null ?在这方面也可以看到 calloc..

标签: c pointers linked-list segmentation-fault


【解决方案1】:

您的“字符串”(char 缓冲区)是列表节点结构的一部分。它不会与节点分开分配,因此不需要释放。您需要做的就是释放节点。

【讨论】:

  • 好的,谢谢!这意味着问题必须在我的代码中的其他地方。我收到的错误消息只是“分段错误”,所以我试图缩小可能的原因。
【解决方案2】:

经验法则是在使用 malloc() 时使用 free()。字符串不需要 free()'d,因为 free()'ing 节点释放分配给整个结构的内存,包括字符串的内存。而且,为什么不使用 gdb 或 valgrind 来调试究竟是哪里出现了故障?在 gdb 中,您可以使用 where 和 print stacktrace 等选项来精确定位发生段错误的位置。现在学习gdb是一笔不错的投资。这部分代码对我来说看起来不错。

【讨论】:

    【解决方案3】:

    只有具有malloc(或类似名称)的东西才需要free

    例如,如果你的结构是这样的:

    struct listNode{
        char *addr;
        struct listNode *next;
    };
    

    然后你会这样分配:

    struct ListNode Node = malloc(sizeof(struct listNode));
    Node.addr = malloc(size of the string);
    

    您必须先释放字符串,然后再释放节点本身。您的字符串作为结构的一部分,具有固定长度,因此没有要释放的字符串。

    但是,您的问题一定是其他问题。尽量避免递归(即您的示例使用递归 - 在大列表上这将导致堆栈溢出)并在释放指针时使指针无效,并在使用它们之前检查指针(非 null)。

    【讨论】:

    • 我想我应该澄清一下:在 malloc 返回且包含字符串的结构上调用 free() 是否会通过尝试释放其中的字符串而导致分段错误?跨度>
    • 没有。 free 不知道也不关心它正在释放的内存块的内容。
    • 好的,谢谢您的所有建议。节点的分配与代码中其他地方的分配完全相同。看来我将不得不在其他地方继续调试。至于递归,这是项目的要求。 @AndrewMedico 感谢您的回答/cmets。现在我真正了解了 C 中内存分配的本质。从 Java 来到 C,这是一个陌生的领域
    • 如果列表变得太大,那么递归将是不可能 - 没有办法绕过它,只能放弃它循环!
    • 程序有一个命令行参数,用于确定此递归的次数......我目前使用的是 10,所以这应该不是问题,但我知道这可能会导致问题。
    【解决方案4】:

    你可能超出了堆栈。

    试试这个:

    void destroyList(struct listNode *pNode){
        while (pNode) {
            struct listNode *x = pNode;
            pNode = pNode->next;
            free(x);
        }
    }
    

    当然,也可能是你传入了一个错误的 pNode,在这种情况下,这将无法修复。

    或者你在别处损坏了堆。

    【讨论】:

      猜你喜欢
      • 2013-12-12
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 2021-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多