You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

动态输入缓冲区大小:如何为逐行读取的输入动态分配内存?

嘿,这个需求我之前做文本处理工具的时候也碰到过,固定大小的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:35:16