使用fgets()按16字节分块读取至换行符的问题及合并需求
问题解决方案
一、解决fgets按换行分割读取的问题
fgets本身会在遇到\n时停止读取,但你的问题出在分块大小设置与fgets参数的配合上:fgets的第二个参数是「最大读取字节数(包含终止符\0)」,你当前定义BUF_SIZE=16却传入BUF_SIZE+1,导致每次最多读16个字符(含\0),当单行内容超过15个有效字符时,fgets会直接截断,无法识别换行并停止。
要实现「遇\n即停止读取、每次分块最多读16字节、总读取不超128字节」,需要手动检查读取内容中是否包含换行符,核心逻辑:
- 每次读取后,用
strchr查找\n,存在则说明当前行读取完成,可单独处理 - 若不存在换行符,继续读取下一块,但需监控总读取字节数不超上限
二、合并读取片段到char*变量
预先分配一个128字节的总缓冲区(含终止符),用变量跟踪已使用字节数,每次读取后将分块内容追加到总缓冲区,同时避免溢出。
完整修正代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define CHUNK_SIZE 16 // 每次分块读取的最大有效字节数(不含'\0') #define MAX_TOTAL 128 // 最大总读取字节数(含'\0') int main() { // 分配分块缓冲区:CHUNK_SIZE+1 用于存储终止符'\0' char *chunk_buf = malloc(sizeof(char) * (CHUNK_SIZE + 1)); // 分配总缓冲区:用calloc初始化全0,避免垃圾数据 char *total_buf = calloc(MAX_TOTAL, sizeof(char)); if (!chunk_buf || !total_buf) { perror("内存分配失败"); return 1; } size_t total_used = 0; // 记录总缓冲区已使用字节数(不含'\0') while (total_used < MAX_TOTAL - 1) { // 预留一个字节给终止符 // fgets最多读取CHUNK_SIZE个有效字符(第二个参数为CHUNK_SIZE+1) if (!fgets(chunk_buf, CHUNK_SIZE + 1, stdin)) { break; // 读取结束或出错 } size_t chunk_len = strlen(chunk_buf); // 检查是否超过总容量上限,超出则截断 if (total_used + chunk_len >= MAX_TOTAL) { chunk_len = MAX_TOTAL - total_used - 1; chunk_buf[chunk_len] = '\0'; } // 将分块内容追加到总缓冲区 strncat(total_buf, chunk_buf, chunk_len); total_used += chunk_len; // 检测换行符,处理完整行 char *newline_pos = strchr(chunk_buf, '\n'); if (newline_pos != NULL) { printf("完整行:%.*s", (int)(newline_pos - chunk_buf + 1), chunk_buf); } } // 打印合并后的全部内容 printf("\n合并后总内容:\n%s", total_buf); free(chunk_buf); free(total_buf); return 0; }
关键说明
- 换行检测:通过
strchr定位\n,一旦找到即可判定当前行读取完成,单独处理该行 - 分块控制:fgets第二个参数设为
CHUNK_SIZE+1,确保每次最多读取16个有效字符(含\n),自动添加终止符 - 容量限制:用
total_used跟踪已用字节数,保证总内容不超过128字节(含终止符) - 内存安全:用
calloc初始化总缓冲区,strncat替代strcat避免溢出
测试验证
执行echo -e "ls -l\nls -l\nls -l" | ./mycode(需加-e让echo解析转义字符),会输出3行完整的ls -l,合并后的总内容也包含这三行。
内容的提问来源于stack exchange,提问作者Joaquín Ayala Filardi
相关产品推荐
相关产品推荐

