使用open/read等系统调用打印文件前10行时行数≤10输出乱码如何修复
问题根因
- 核心问题:
read系统调用仅读取文件原始二进制内容,不会自动在缓冲区末尾追加字符串结束符\0。你用malloc申请的缓冲区未初始化,文件内容之后的内存都是随机值,原有逻辑中for(int i = 0;buff[i] != '\0'; i++)的终止条件完全不可靠,当文件行数不足10行时,会读取到文件内容之外的随机垃圾数据,直到碰巧遇到\0才停止,这就是输出垃圾值的原因。 - 附加问题1:函数返回值声明为
void,错误分支写return NULL属于语法错误,会触发编译告警。 - 附加问题2:未处理
read调用失败返回-1的异常场景。 - 附加问题3:遍历缓冲区的边界判断错误,应该以实际读取到的总字节数作为终止边界,而非依赖不存在的
\0。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> // 包含read/close等系统调用的标准声明 void print_file_rows(char *path) { int fd = open(path, O_RDONLY); if (fd < 0) { perror("打开文件失败"); return; // 修正返回值错误 } size_t size = 100; size_t offset = 0; ssize_t res; // read返回值为ssize_t类型,与标准定义对齐 char *buff = malloc(size); if (!buff) { perror("内存分配失败"); close(fd); return; } while((res = read(fd, buff + offset, 100)) > 0) // 仅读成功时继续循环 { offset += res; if (offset + 100 > size) { size *= 2; char *new_buff = realloc(buff, size); if (!new_buff) { perror("内存扩容失败"); free(buff); close(fd); return; } buff = new_buff; } } if (res == -1) { // 处理读取失败的异常场景 perror("读取文件失败"); free(buff); close(fd); return; } close(fd); int j = 0; // 修正遍历边界:仅访问实际读取到的offset个字节,避免读到垃圾数据 for(int i = 0; i < offset; i++) { if(j == 10) { break; } if(buff[i] == '\n') { j++; } printf("%c", buff[i]); } free(buff); } int main() { print_file_rows("a.txt"); return 0; }
关键修改点说明
- 补充了系统调用依赖的头文件,修正了返回值、变量类型的语法错误
- 补充了内存分配、系统调用的错误处理逻辑,避免程序异常崩溃
- 把遍历缓冲区的终止条件从判断
buff[i] != '\0'改为i < offset,只会访问实际从文件读取到的内容,彻底解决垃圾值输出问题 - 调整
read的返回值判断逻辑,明确区分读结束和读失败两种场景
内容的提问来源于stack exchange,提问作者Inakis Girou
相关产品推荐
相关产品推荐

