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); }
关键修复点说明
ft_substr逻辑修正
- 移除了错误的长度计算逻辑,改为取
len和剩余字符串长度的最小值,避免越界 - 拷贝时使用
start + i的索引方式,避免修改原字符串的指针 - 移除了不必要的
free(s),因为该函数的职责只是生成子串,不应释放原字符串
- 移除了错误的长度计算逻辑,改为取
get_next_line的内存管理
- 更新静态变量
content前,先释放旧的内存块,避免泄漏 - 文件读取完毕(
content为空)时,主动释放content并置为NULL - 提取行后,正确处理剩余内容,若没有剩余则将
content置为NULL
- 更新静态变量
main函数的资源清理
- 使用循环读取直到文件结束,确保所有行都被处理
- 每次读取后立即释放返回的
line指针 - 关闭文件描述符,避免资源泄漏
ft_strjoin的健壮性提升
- 增加了
s1分配失败时的处理逻辑 - 提前计算字符串长度,避免重复调用
ft_strlen
- 增加了
内容的提问来源于stack exchange,提问作者deboracaracol
相关产品推荐
相关产品推荐

