读取超大数字文件存数组时内存分配失败,求解决方案
问题描述
给定一个数字文件,需要找出所有满足特定条件的非连续数对。为完成任务,计划将约1.5×10^9个数字(文件大小约11000KB,数字范围0 < 数字 ≤ 100000)全部读取并存储到数组中。
文件格式示例:
10 20 30 40 50 60
最初尝试创建常规数组int arr[150000000],因栈溢出失败;改用calloc实现动态数组,代码如下:
#include<stdio.h> #include<stdlib.h> int main() { FILE *file = fopen("nums.txt", "r"); int str_size = 8; char str[str_size]; // 0 < number <= 100000,长度8足够(6位数字+换行符+终止符) int size = 2000; //初始容量 int *a = calloc(size, sizeof(int)); //数组 int i = 0; while( ((fgets(str, str_size, file) ) != NULL)) { //逐行读取,每行一个数字 if(atoi(str)!=0) //过滤空行(fgets会读到换行符,转换后为0) { a[i] = atoi(str); //字符串转整数并存入数组 i++; } a = realloc(a, sizeof(int)*(size*2) ); //每次循环都扩容为原来的2倍 size = size * 2; } a[i] = -1; //用-1标记数组末尾 fclose(file); free(a); return 0; }
处理小文件(100KB)时正常,但处理大文件时报错:
realloc(): invalid next size Aborted (core dumped)
编辑:修正了size变量同步更新的问题后,仍出现Segmentation fault (core dumped)错误。
解决方案
1. 核心问题:直接存储所有数字的内存需求远超常规机器容量
1.5×10^9个int类型数字,按每个int占4字节计算,总内存需求达6GB,这已经超过多数普通机器的物理内存上限,直接全量存入内存根本不现实,这是报错的核心原因。
2. 最优方案:用计数数组替代全量存储
因为数字范围明确为0 < 数字 ≤ 100000,完全可以用一个大小为100001的数组统计每个数字的出现次数,而非存储所有1.5×10^9个数字。这种方式仅需约400KB内存,完全可以轻松容纳,后续处理数对逻辑也能基于计数数组快速完成。
示例代码思路:
#include<stdio.h> #include<stdlib.h> #define MAX_NUM 100000 int main() { FILE *file = fopen("nums.txt", "r"); if (!file) { perror("Failed to open file"); return 1; } // 初始化计数数组,所有元素初始为0 int *counts = calloc(MAX_NUM + 1, sizeof(int)); if (!counts) { perror("Failed to allocate memory"); fclose(file); return 1; } char str[8]; while (fgets(str, 8, file) != NULL) { int num = atoi(str); if (num > 0 && num <= MAX_NUM) { // 确保数字在有效范围内 counts[num]++; } } // 此处可基于counts数组处理数对逻辑 // 例如查找满足条件的数对(x,y),直接通过counts[x]和counts[y]判断存在性及数量 fclose(file); free(counts); return 0; }
3. 若需保留数字顺序:分批次处理或用内存映射
如果数对逻辑依赖数字的顺序(比如需要判断位置关系),无法用计数数组,可采用以下两种方式:
- 分批次读取:每次读取部分数字到内存,处理完当前批次的数对后释放内存,再读取下一批;
- 内存映射文件:使用
mmap让操作系统自动管理内存与磁盘的交换,避免手动扩容的繁琐操作。
4. 原代码的逻辑错误修复(仅作参考,无法解决大内存问题)
即使不考虑内存容量,原代码也存在严重逻辑问题:
- 每次循环都扩容,不管数组是否已满,导致内存浪费和频繁分配;
- 未检查
realloc返回值,分配失败会丢失原指针,引发内存泄漏; atoi(str)!=0的判断不可靠,无法准确过滤无效输入。
修复后的代码示例:
#include<stdio.h> #include<stdlib.h> #include<string.h> int main() { FILE *file = fopen("nums.txt", "r"); if (!file) { perror("Failed to open file"); return 1; } int str_size = 8; char str[str_size]; int size = 2000; int *a = calloc(size, sizeof(int)); if (!a) { perror("Failed to allocate memory"); fclose(file); return 1; } int i = 0; while (fgets(str, str_size, file) != NULL) { // 去掉换行符 str[strcspn(str, "\n")] = '\0'; // 用strtol判断有效数字 char *endptr; long num = strtol(str, &endptr, 10); if (endptr != str && num > 0 && num <= 100000) { // 数组满了才扩容 if (i >= size) { int new_size = size * 2; int *new_a = realloc(a, new_size * sizeof(int)); if (!new_a) { perror("Failed to reallocate memory"); free(a); fclose(file); return 1; } a = new_a; size = new_size; } a[i++] = (int)num; } } printf("Total numbers read: %d\n", i); fclose(file); free(a); return 0; }
内容的提问来源于stack exchange,提问作者Rodion Iskhakov
相关产品推荐
相关产品推荐

