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

如何用C语言逐行读取未知长度TXT文件并实现归并排序?

解决逐行读取整数并归并排序的问题

嘿,我完全懂你纠结的点——既要安全读取每行的大量整数,又不想因为缓冲区大小踩坑,对吧?咱们一步步拆解这两个方案,给你靠谱的解决思路:

方案1:优化版fgets + strtok_r/strtol(解决缓冲区溢出问题)

你担心的缓冲区大小问题其实很好解决:既然每行最多10000个整数,咱们可以先估算出每行的最大字符长度。假设每个整数是32位有符号数(最大是2147483647,10位),加上每个数之间的空格(或制表符),再加上换行符,每行的最大字符数大概是:10000*(10+1) + 2 = 110002(多留几个字节容错)。

基于这个估算,你可以静态分配足够大的栈缓冲区(128KB完全够用,栈默认大小一般是几MB,完全不会溢出),或者用动态分配更灵活。另外,推荐用线程安全的strtok_r替代strtok,避免潜在的多线程问题;strtol要做好错误处理,确保转换的是有效整数。

示例代码片段

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>

#define MAX_PER_LINE 10000
#define MAX_LINE_LEN 128000 // 足够容纳最大行的字符数

int main() {
    FILE *fp = fopen("data.txt", "r");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    // 用动态数组存储所有行的整数(每行一个子数组,记录每行的元素个数)
    int **all_lines = NULL;
    int *line_sizes = NULL;
    int line_count = 0;

    char line_buf[MAX_LINE_LEN];
    while (fgets(line_buf, sizeof(line_buf), fp) != NULL) {
        // 处理可能的截断(如果行超长,这里需要额外处理,但根据题目假设不会发生)
        size_t len = strlen(line_buf);
        if (len > 0 && line_buf[len-1] != '\n' && !feof(fp)) {
            fprintf(stderr, "Warning: Line %d exceeds buffer size, truncated\n", line_count+1);
            // 跳过剩余字符直到换行
            while (fgetc(fp) != '\n' && !feof(fp));
        }

        // 分割并转换整数
        char *saveptr;
        char *token = strtok_r(line_buf, " \t\n", &saveptr);
        int *current_line = malloc(MAX_PER_LINE * sizeof(int));
        int count = 0;

        while (token != NULL && count < MAX_PER_LINE) {
            errno = 0;
            long num = strtol(token, NULL, 10);
            if (errno != 0 || num < INT_MIN || num > INT_MAX) {
                fprintf(stderr, "Invalid integer: %s\n", token);
                token = strtok_r(NULL, " \t\n", &saveptr);
                continue;
            }
            current_line[count++] = (int)num;
            token = strtok_r(NULL, " \t\n", &saveptr);
        }

        // 调整数组大小(如果实际元素数小于MAX_PER_LINE)
        current_line = realloc(current_line, count * sizeof(int));
        if (!current_line) {
            perror("Failed to realloc");
            return 1;
        }

        // 存入总数组
        all_lines = realloc(all_lines, (line_count+1) * sizeof(int*));
        line_sizes = realloc(line_sizes, (line_count+1) * sizeof(int));
        if (!all_lines || !line_sizes) {
            perror("Failed to realloc");
            return 1;
        }
        all_lines[line_count] = current_line;
        line_sizes[line_count++] = count;
    }

    // 这里可以调用归并排序逻辑,比如先对每行排序,再归并所有行,或者直接合并成一个大数组排序
    // ...

    // 记得释放内存
    for (int i = 0; i < line_count; i++) {
        free(all_lines[i]);
    }
    free(all_lines);
    free(line_sizes);
    fclose(fp);
    return 0;
}

方案2:更省心的fscanf方案(跳过行的限制)

如果你的归并排序不需要保留“每行”的结构,只是要把所有整数存入一个大数组,那fscanf其实更简单——它会自动跳过所有空白字符(包括空格、换行、制表符),不需要处理行分割的逻辑。而且完全不用担心缓冲区的问题,因为它直接读取整数。

示例代码片段

#include <stdio.h>
#include <stdlib.h>

#define INIT_CAPACITY 100000 // 初始数组容量,可根据实际调整

int main() {
    FILE *fp = fopen("data.txt", "r");
    if (!fp) {
        perror("Failed to open file");
        return 1;
    }

    int *nums = malloc(INIT_CAPACITY * sizeof(int));
    if (!nums) {
        perror("Failed to malloc");
        return 1;
    }
    int count = 0;
    int capacity = INIT_CAPACITY;
    int num;

    // 逐个读取整数
    while (fscanf(fp, "%d", &num) == 1) {
        if (count >= capacity) {
            // 扩容数组(比如每次翻倍)
            capacity *= 2;
            int *temp = realloc(nums, capacity * sizeof(int));
            if (!temp) {
                perror("Failed to realloc");
                free(nums);
                fclose(fp);
                return 1;
            }
            nums = temp;
        }
        nums[count++] = num;
    }

    // 调整到实际大小
    nums = realloc(nums, count * sizeof(int));
    if (!nums && count > 0) {
        perror("Failed to realloc");
        return 1;
    }

    // 调用归并排序函数对nums数组排序
    // merge_sort(nums, 0, count-1);
    // ...

    free(nums);
    fclose(fp);
    return 0;
}

关键提醒

  • 如果必须保留每行的结构,优先用方案1;如果只需要所有整数的集合,方案2更高效。
  • 所有动态分配的内存记得在使用完后释放,避免内存泄漏。
  • 一定要处理文件打开失败、内存分配失败、整数转换错误等异常情况,让程序更健壮。

内容的提问来源于stack exchange,提问作者李智修

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:13:06