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

realloc用法是否正确?翻倍扩容素数标记数组时始终失败

素数排查函数中realloc扩容失败问题排查

问题描述

编写素数排查函数时,尝试在数组达到容量限制时用realloc将其大小翻倍,但每次realloc都执行失败,怀疑用法有误。

相关代码片段

if (iNum >= ArrSize) {
    ArrSize = ArrSize * 2;
    NumArr = realloc(NumArr, ArrSize * sizeof(int));

    if (NumArr == NULL) {
        printf("Array not reallocated!\n");
        printf("Array size was: %d", ArrSize);
        return 1;
    }
}

运行输出

Enter the amount of prime numbers to list: 5
2
3
5
Array not reallocated!
Array size was: 8

完整函数代码

int PrimeChecker(int nPrime) {
    size_t ArrSize = nPrime - 1;
    int iFlag, CurPrime;
    int j = 1;
    
    int *NumArr = calloc(ArrSize, sizeof(int)); // Array (Pointer) of flags for filtering non-prime numbers

    if (NumArr == NULL) {
        fprintf(stderr, "Array not allocated!");
        return 1;
    }

    for (int iNum = 2; CurPrime != nPrime + 1; iNum++) {

        if (NumArr[iNum] != 1) {
            printf("%d\n", iNum);
            CurPrime++;
            iFlag = iNum;

            for (; (iFlag * j) <= nPrime; j++) {
                NumArr[iFlag * j] = 1;
            }
            j = 0;

            if (iNum >= ArrSize) {
                ArrSize = ArrSize * 2;
                NumArr = realloc(NumArr, ArrSize * sizeof(int));

                if (NumArr == NULL) {
                    fprintf(stderr, "Array not reallocated!\n");
                    printf("Array size was: %d", ArrSize);
                    return 1;
                }
            }
        }
    }
    free(NumArr);
    return 0;
}

int main() {
    int nPrime; // User input for number of primes to list
    printf("Enter the amount of prime numbers to list: ");
    scanf("%d", &nPrime);
    PrimeChecker(nPrime);
}

问题根源分析

  1. 数组索引越界访问:
    NumArr的大小为ArrSize,有效索引范围是0 ~ ArrSize-1,但代码中直接用iNum作为索引访问NumArr[iNum]。当iNum >= ArrSize时,已经属于越界访问,会破坏内存结构,导致后续realloc无法正常工作。

  2. 局部变量未初始化:
    CurPrime未初始化,初始值为随机值,导致循环条件CurPrime != nPrime +1行为不可预测,循环无法在找到足够素数后终止,iNum会持续增大,触发不必要的扩容操作。

  3. 标记非素数时的越界问题:
    在标记iFlag的倍数时,iFlag*j可能超过当前数组的最大索引,同样会造成越界访问,进一步破坏内存。

修复方案

修改后的代码

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

int PrimeChecker(int nPrime) {
    if (nPrime <= 0) {
        fprintf(stderr, "Invalid input! Please enter a positive integer.\n");
        return 1;
    }

    size_t ArrSize = 4; // 初始数组大小,可根据需求调整
    int CurPrime = 0;   // 初始化已找到的素数数量
    int iFlag;
    int j;
    
    int *NumArr = calloc(ArrSize, sizeof(int));
    if (NumArr == NULL) {
        fprintf(stderr, "Failed to allocate initial array!\n");
        return 1;
    }

    for (int iNum = 2; CurPrime < nPrime; iNum++) {
        // 先检查扩容,避免访问数组时越界
        if (iNum >= ArrSize) {
            size_t newSize = ArrSize * 2;
            // 用临时指针接收realloc结果,避免原指针丢失
            int *newArr = realloc(NumArr, newSize * sizeof(int));
            if (newArr == NULL) {
                fprintf(stderr, "Failed to reallocate array!\n");
                fprintf(stderr, "Requested size: %zu\n", newSize);
                free(NumArr); // 释放原有内存,避免泄漏
                return 1;
            }
            NumArr = newArr;
            // 初始化扩容后的新内存为0,保持标记数组一致性
            memset(NumArr + ArrSize, 0, (newSize - ArrSize) * sizeof(int));
            ArrSize = newSize;
        }

        if (NumArr[iNum] != 1) {
            printf("%d\n", iNum);
            CurPrime++;
            iFlag = iNum;

            // 标记当前素数的所有倍数为非素数(从2倍开始)
            j = 2;
            while ((size_t)iFlag * j < ArrSize) {
                NumArr[iFlag * j] = 1;
                j++;
            }
            // 若倍数超过当前数组大小,后续扩容后再处理:
            // 合数的最小质因数必然小于自身,后续遍历到该数时会被标记
        }
    }
    free(NumArr);
    return 0;
}

int main() {
    int nPrime;
    printf("Enter the amount of prime numbers to list: ");
    if (scanf("%d", &nPrime) != 1) {
        fprintf(stderr, "Input error!\n");
        return 1;
    }
    return PrimeChecker(nPrime);
}

关键修改点

  • 初始化CurPrime为0,将循环条件改为CurPrime < nPrime,确保找到指定数量的素数后终止循环。
  • 将扩容检查移至访问NumArr[iNum]之前,彻底避免越界访问。
  • 使用临时指针接收realloc的返回值,防止realloc失败时丢失原内存指针,同时释放原有内存避免泄漏。
  • 对扩容后的新内存区域用memset初始化为0,保证标记数组的所有元素初始状态一致。
  • 调整标记倍数的逻辑,从2倍开始标记(跳过素数自身),并确保标记的索引不超过当前数组范围。

内容的提问来源于stack exchange,提问作者Terrible-Shid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:17:04