You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用free()删除链表元素数据时触发free(): invalid pointer错误求助

问题:调用free()释放链表元素数据时触发无效指针错误

我正在完成一项编程练习,要求实现函数ft_list_remove_if:移除链表中所有经cmp函数与data_ref对比返回0的元素,且需调用free_fct释放待删除元素的数据。函数原型为:

void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)(), void (*free_fct)(void *));

我在调用free()释放数据元素时,始终触发free() invalid pointer Aborted (core dumped)错误。以下是我的相关代码:

typedef struct llist { 
    void *a;
    struct llist *next;
} t_list;

t_list *ft_create_elem(void *data)
{
    t_list *ptr;
    ptr = NULL;
    ptr = malloc(sizeof(t_list));
    ptr->a = data;
    ptr->next = NULL;   /*NOTE 我另有一个函数负责将新创建的元素链接到前一个元素*/
    return (ptr);
}

int ft_strcmp(char *s1, char *s2)
{
    int i;

    i = 0;
    while (s1[i] == s2[i] && s1[i] != '\0' && s2[i] != '\0')
    {
        i++;
    }
    return (s1[i] - s2[i]);
}

void *ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)(), void (*free_fct)(void *))
{  
    while(*begin_list)
    {
        if (cmp(((*begin_list)->a), data_ref) == 0)
            free_fct((*begin_list)->a);               
        *begin_list = (*begin_list)->next;
    }
}

我通过ft_list_remove_if(&toprint, "Third", ft_strcmp, free);调用该函数,toprint是包含5个元素(数据分别为"First"、"Second"、"Third"、"Fourth"、"Fifth")的链表头指针,目标是删除"Third"元素。

我可以修改(*begin_list)->a的内容,但无法释放其中的数据,想请教问题所在:(*begin_list)->a是不是不能传给free()的有效指针?是不是因为ft_create_elem中直接将data赋值给void *a?尝试赋值a = &data时输出乱码,该如何解决?


问题原因与解决方法

  • 核心问题:你在释放字符串字面量的指针
    你创建链表时传入的"First""Third"这类是字符串字面量,它们存储在程序的只读数据段,不是通过malloc/calloc/realloc分配的堆内存。free()只能释放堆上的内存,对只读段指针调用free()必然触发无效指针错误。

  • 直接赋值data的问题
    ft_create_elem里ptr->a = data只是把传入的指针值直接存起来。如果传入的是字符串字面量,ptr->a指向的就是只读内存,不能被free();只有当传入的是堆上分配的字符串(比如malloc出来的),free()才合法。

  • a = &data乱码的原因
    data是ft_create_elem的函数参数,属于栈上的局部变量。函数执行完后栈帧被销毁,&data指向的内存会被回收复用,后续访问就会出现乱码,这是典型的悬垂指针问题。

  • 具体解决步骤

    1. 创建元素时深拷贝字符串到堆内存:修改ft_create_elem,对传入的字符串做深拷贝,用strdup或者自己实现malloc+strcpy:

      t_list *ft_create_elem(void *data)
      {
          t_list *ptr = malloc(sizeof(t_list));
          if (!ptr) return NULL;
          // 假设data是字符串,做深拷贝
          ptr->a = strdup((char*)data);
          ptr->next = NULL;
          return ptr;
      }
      

      这样ptr->a指向堆内存,调用free()就合法了。

    2. 修复ft_list_remove_if的逻辑漏洞:你现在的函数只释放了数据,没移除链表节点,还会丢失整个链表指针。正确逻辑如下:

      void ft_list_remove_if(t_list **begin_list, void *data_ref, int (*cmp)(), void (*free_fct)(void *))
      {  
          t_list *curr;
          t_list *tmp;
      
          // 先处理链表头部需要删除的节点
          while (*begin_list && cmp((*begin_list)->a, data_ref) == 0) {
              curr = *begin_list;
              *begin_list = curr->next;
              free_fct(curr->a);
              free(curr); // 还要释放链表节点本身
          }
      
          // 处理中间和尾部的节点
          curr = *begin_list;
          while (curr && curr->next) {
              if (cmp(curr->next->a, data_ref) == 0) {
                  tmp = curr->next;
                  curr->next = tmp->next;
                  free_fct(tmp->a);
                  free(tmp);
              } else {
                  curr = curr->next;
              }
          }
      }
      

      这个版本会正确移除节点,同时释放数据和节点内存,避免内存泄漏和逻辑错误。

内容的提问来源于stack exchange,提问作者shamalamadingdong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:31:29