如何用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,提问作者李智修
相关产品推荐
相关产品推荐

