C实现_unsetenv编辑.bashrc删环境变量时末行多出重复文本
问题根因
末尾重复追加最后一行片段的问题是3个代码bug叠加导致的,没有特殊逻辑错误:
- 文件未截断残留旧内容:你用
r+模式打开文件后从起始位置写入新内容,但删除一行后新内容总长度比原文件短,写完后没有截断文件,原文件末尾多出来的旧内容没有被清理,刚好就是你看到的重复的SOME='CHANGED'片段。 temp_split内存分配大小错误:你写的temp_split = malloc(sizeof(char) * lines - 1)是按1字节的char类型分配空间,但temp_split是char**类型的指针数组,64位系统下每个指针占8字节,实际分配空间远小于需求,造成内存越界写入,属于未定义行为。- 隐藏野指针bug:
string_count函数中将栈上局部变量words的地址存入返回值,函数退出后该地址指向的栈内存会被回收,成为野指针,当前场景没触发崩溃只是巧合。
修复方案
按以下顺序修改代码即可解决问题:
- 修正
temp_split的内存分配
将错误的分配代码替换为正确的指针数组分配:// 原错误代码:temp_split = malloc(sizeof(char) * lines - 1); temp_split = malloc(sizeof(char*) * (lines - 1)); - 写文件前重置指针,写完后截断文件
打开文件、完成mmap后,先把文件指针重置到起始位置;所有内容写入完成后,先刷新IO缓冲区,再将文件截断到当前写入位置的长度,清除旧内容残留:stream = fopen(filename, "r+"); if (!stream) return (-1); rewind(stream); // 新增:指针回到文件开头 f_d = stream->_fileno; // ... 中间的mmap、split、循环写入逻辑不变 ... // 循环写入完成后新增以下逻辑 fflush(stream); ftruncate(f_d, ftell(stream)); // 截断文件到实际写入长度 - 修复
string_count的野指针问题
不要返回栈上局部变量的地址,给行数统计值也分配堆内存:
对应释放内存时,要先释放// 原错误代码:how_many[0] = &words; how_many[0] = malloc(sizeof(int)); *how_many[0] = words;how_many[0]和how_many[1]指向的堆空间,再释放how_many本身,避免内存泄漏。 - 补全资源释放逻辑
函数返回前记得释放所有申请的堆内存、关闭文件、释放mmap映射:- 写完文件后先调用
munmap(map, st.st_size)释放内存映射 - 遍历
split数组释放每个字符串,再释放split本身 - 释放
temp_split、to_search、filename等malloc申请的内存 - 最后调用
fclose(stream)关闭文件流
- 写完文件后先调用
修改完成后再执行删除FOO变量的操作,.bashrc文件会正确保留除目标行外的所有内容,不会再出现末尾重复文本的问题。
内容的提问来源于stack exchange,提问作者Marlon
相关产品推荐
相关产品推荐

