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); }
问题根源分析
数组索引越界访问:
NumArr的大小为ArrSize,有效索引范围是0 ~ ArrSize-1,但代码中直接用iNum作为索引访问NumArr[iNum]。当iNum >= ArrSize时,已经属于越界访问,会破坏内存结构,导致后续realloc无法正常工作。局部变量未初始化:
CurPrime未初始化,初始值为随机值,导致循环条件CurPrime != nPrime +1行为不可预测,循环无法在找到足够素数后终止,iNum会持续增大,触发不必要的扩容操作。标记非素数时的越界问题:
在标记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
相关产品推荐
相关产品推荐

