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

读取超大数字文件存数组时内存分配失败,求解决方案

问题描述

给定一个数字文件,需要找出所有满足特定条件的非连续数对。为完成任务,计划将约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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 21:35:26