动态输入缓冲区大小:如何为逐行读取的输入动态分配内存?
嘿,这个需求我之前做文本处理工具的时候也碰到过,固定大小的fgets()确实容易碰到长行截断的问题,用fgetc()结合动态扩容缓冲区是非常稳妥的方案,我给你详细拆解下实现思路和代码示例:
动态读取整行的核心实现思路
其实不用先计数再分配内存(那样还要读两遍行内容,效率低),我们可以边读字符边动态扩容缓冲区,具体步骤是:
- 先给一个初始的缓冲区大小(比如128字节,这个值可以根据你的场景调整),用
malloc分配内存 - 用
fgetc()逐个读取输入字符,每读一个就检查缓冲区是否还有空间 - 如果缓冲区满了,就用
realloc()把缓冲区大小翻倍(这种扩容策略能把整体时间复杂度控制在O(n),比每次加固定字节高效很多) - 读到换行符或者EOF时停止读取,最后给缓冲区加上字符串结束符
'\0' - 一定要记得在使用完缓冲区后用
free()释放,避免内存泄漏
完整的动态读行函数实现
下面是一个可以直接用的dynamic_getline()函数,还会返回行的长度:
#include <stdio.h> #include <stdlib.h> char* dynamic_getline(size_t* out_length) { // 初始缓冲区大小,可根据实际场景调整 size_t buffer_size = 128; char* buffer = malloc(buffer_size); if (!buffer) { perror("malloc failed"); return NULL; } size_t current_length = 0; int c; // 逐字符读取,直到EOF或换行 while ((c = fgetc(stdin)) != EOF && c != '\n') { // 检查缓冲区是否即将满(要留位置给'\0') if (current_length + 1 >= buffer_size) { buffer_size *= 2; char* temp_buffer = realloc(buffer, buffer_size); if (!temp_buffer) { perror("realloc failed"); free(buffer); return NULL; } buffer = temp_buffer; } buffer[current_length++] = (char)c; } // 如果读到换行符,把它也存进缓冲区 if (c == '\n') { if (current_length + 1 >= buffer_size) { buffer_size += 1; char* temp_buffer = realloc(buffer, buffer_size); if (!temp_buffer) { perror("realloc failed"); free(buffer); return NULL; } buffer = temp_buffer; } buffer[current_length++] = '\n'; } // 最后添加字符串结束符 if (current_length + 1 >= buffer_size) { buffer_size += 1; char* temp_buffer = realloc(buffer, buffer_size); if (!temp_buffer) { perror("realloc failed"); free(buffer); return NULL; } buffer = temp_buffer; } buffer[current_length] = '\0'; // 返回行长度(如果传入了指针的话) if (out_length) { *out_length = current_length; } return buffer; }
结合单词匹配的使用示例
假设你要查找的目标单词是"example",可以这样把动态读行和匹配逻辑结合起来:
#include <string.h> int main() { size_t line_len; char* line; const char* target_word = "example"; size_t target_len = strlen(target_word); // 逐行读取输入 while ((line = dynamic_getline(&line_len)) != NULL) { // 如果行长度比目标单词短,直接跳过 if (line_len < target_len) { free(line); continue; } // 遍历行内容,查找所有匹配的单词 char* match_pos = line; while ((match_pos = strstr(match_pos, target_word)) != NULL) { // 计算起止位置(这里是从0开始的索引,如果你需要从1开始就加1) size_t start_idx = match_pos - line; size_t end_idx = start_idx + target_len - 1; printf("找到匹配单词 \"%s\",起止位置:%zu - %zu\n", target_word, start_idx, end_idx); // 移动指针,避免重复匹配同一个位置 match_pos += target_len; } // 一定要释放缓冲区! free(line); } return 0; }
几个需要注意的细节
- 错误处理:每个
malloc和realloc都要检查返回值,避免空指针访问导致程序崩溃 - 扩容策略:用翻倍的方式扩容能减少
realloc的调用次数,提升效率;如果你的场景里长行特别多,初始缓冲区可以设大一点 - 换行符处理:上面的函数会保留换行符,如果不需要的话,可以把处理换行符的代码删掉
- 内存泄漏:每次用完
dynamic_getline()返回的缓冲区必须用free()释放,尤其是在循环里,不然会积累大量内存泄漏
内容的提问来源于stack exchange,提问作者Dennis Fagerblad
相关产品推荐
相关产品推荐

