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

C语言get_next_line函数内存泄漏与段错误排查求助

修复get_next_line的内存泄漏与段错误问题

核心问题梳理

你的代码主要存在以下几个导致内存泄漏和段错误的问题:

  • static变量未正确释放:get_next_line中更新静态变量content时,直接覆盖旧指针,导致原内存块无法释放
  • ft_substr逻辑错误:计算子串长度的逻辑混乱,可能导致越界访问;错误的free(s)(虽已注释,但逻辑本身不合理)
  • 返回值未释放:main中没有释放get_next_line返回的字符串,且未关闭文件描述符
  • 末尾处理缺失:当文件读取完毕后,静态变量content未被释放,造成泄漏

修复后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define BUFFER_SIZE 1024

size_t  ft_strlen(char *s)
{
    size_t  i;

    if (!s)
        return (0);
    i = 0;
    while (s[i] != '\0')
        i++;
    return (i);
}

char    *ft_strchr(char *s, int c)
{
    size_t  i;

    i = 0;
    if (!s)
        return (NULL);
    while ((s[i] != '\0') && (s[i] != (unsigned char)c))
        i++;
    if ((s[i] == (unsigned char)c) || (c == '\0'))
        return ((char *)&s[i]);
    return (NULL);
}

char    *ft_substr(char *s, unsigned int start, size_t len)
{
    size_t  i;
    size_t  s_len;
    char    *sub;

    if (!s)
        return (NULL);
    s_len = ft_strlen(s);
    if (start >= s_len)
    {
        sub = malloc(1 * sizeof(char));
        if (!sub)
            return (NULL);
        sub[0] = '\0';
        return (sub);
    }
    // 实际可拷贝的长度:取len和剩余长度的最小值
    if (len > s_len - start)
        len = s_len - start;
    sub = malloc((len + 1) * sizeof(char));
    if (!sub)
        return (NULL);
    i = 0;
    while (i < len && s[start + i] != '\0')
    {
        sub[i] = s[start + i];
        i++;
    }
    sub[i] = '\0';
    return (sub);
}

char    *ft_strjoin(char *s1, char *s2)
{
    char    *cat;
    size_t  i;
    size_t  j;
    size_t  s1_len;
    size_t  s2_len;

    if (!s1 && !s2)
        return (NULL);
    if (!s1)
    {
        s1 = malloc(sizeof(char) * 1);
        if (!s1)
            return (NULL);
        s1[0] = '\0';
    }
    s1_len = ft_strlen(s1);
    s2_len = ft_strlen(s2);
    cat = malloc((s1_len + s2_len + 1) * sizeof(char));
    if (!cat)
    {
        free(s1);
        return (NULL);
    }
    i = 0;
    while (s1[i] != '\0')
    {
        cat[i] = s1[i];
        i++;
    }
    j = 0;
    while (s2[j] != '\0')
        cat[i++] = s2[j++];
    cat[i] = '\0';
    free(s1);
    return (cat);
}

char    *ft_content(int fd, char *content)
{
    char    *buf;
    int     buf_nb;

    buf = malloc((BUFFER_SIZE + 1) * sizeof(char));
    if (!buf)
    {
        free(content);
        return (NULL);
    }
    buf_nb = 1;
    while (!ft_strchr(content, '\n') && buf_nb != 0)
    {
        buf_nb = read(fd, buf, BUFFER_SIZE);
        if (buf_nb == -1)
        {
            free(buf);
            free(content);
            return (NULL);
        }
        buf[buf_nb] = '\0';
        content = ft_strjoin(content, buf);
        if (!content)
        {
            free(buf);
            return (NULL);
        }
    }
    free(buf);
    return (content);
}

char    *get_next_line(int fd)
{
    static char *content;
    char        *line;
    char        *temp_content;
    int         newline_pos;

    if (fd < 0 || BUFFER_SIZE <= 0)
        return (NULL);
    content = ft_content(fd, content);
    if (!content || content[0] == '\0')
    {
        free(content);
        content = NULL;
        return (NULL);
    }
    // 找到换行符位置
    newline_pos = 0;
    while (content[newline_pos] != '\n' && content[newline_pos] != '\0')
        newline_pos++;
    // 提取当前行(包含换行符如果存在)
    if (content[newline_pos] == '\n')
        line = ft_substr(content, 0, newline_pos + 1);
    else
        line = ft_substr(content, 0, newline_pos);
    if (!line)
    {
        free(content);
        content = NULL;
        return (NULL);
    }
    // 更新content为剩余部分
    if (content[newline_pos] == '\n')
        temp_content = ft_substr(content, newline_pos + 1, ft_strlen(content) - newline_pos - 1);
    else
        temp_content = NULL;
    free(content);
    content = temp_content;
    return (line);
}

int    main(void)
{
    int    fd = open("exemplo.txt", O_RDONLY);
    char    *line;

    if (fd == -1)
    {
        perror("open failed");
        return (1);
    }
    while ((line = get_next_line(fd)) != NULL)
    {
        printf("%s", line);
        free(line); // 释放返回的行
    }
    close(fd); // 关闭文件描述符
    return (0);
}

关键修复点说明

  1. ft_substr逻辑修正

    • 移除了错误的长度计算逻辑,改为取len和剩余字符串长度的最小值,避免越界
    • 拷贝时使用start + i的索引方式,避免修改原字符串的指针
    • 移除了不必要的free(s),因为该函数的职责只是生成子串,不应释放原字符串
  2. get_next_line的内存管理

    • 更新静态变量content前,先释放旧的内存块,避免泄漏
    • 文件读取完毕(content为空)时,主动释放content并置为NULL
    • 提取行后,正确处理剩余内容,若没有剩余则将content置为NULL
  3. main函数的资源清理

    • 使用循环读取直到文件结束,确保所有行都被处理
    • 每次读取后立即释放返回的line指针
    • 关闭文件描述符,避免资源泄漏
  4. ft_strjoin的健壮性提升

    • 增加了s1分配失败时的处理逻辑
    • 提前计算字符串长度,避免重复调用ft_strlen

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 01:47:09