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

C堆分配数组出现未定义行为的原因及修复方案咨询

问题原因分析

你的问题根源在于指针的传递方式:你把factors指针按值传递给了PrimeFactors函数。

在C语言中,函数参数默认是值传递——也就是说,当你把factors传入函数时,函数会创建一个这个指针的副本。当你在函数内部调用realloc时,如果系统需要为数组分配新的内存块(比如你遇到的数组大小>=4的情况),realloc会返回新的内存地址,这个地址只会赋值给函数内部的那个指针副本,而main函数里的原始factors指针完全不知道这个变化,仍然指向原来的旧内存地址。

旧的内存地址在realloc完成后已经被系统回收或者重新分配了,这时候main函数再去访问这个地址,自然会读到垃圾值,触发未定义行为。

从你的实际输出也能清晰看到这个问题:当realloc到大小4时,函数内部的地址变成了0x5626aa1812b0,但main里的地址还是最初的0x5626aa180260,两者已经不一致了。


修复方案

有两种常见的方法可以解决这个问题,都是为了让main函数能获取到realloc后的新指针地址:

方法1:传递指针的指针(推荐,兼容你当前的函数返回值设计)

我们通过传递factors指针的地址(也就是二级指针),让函数可以直接修改main里的原始指针变量。

修改步骤:

  1. 修改PrimeFactors函数的参数,把unsigned long long* factors改成unsigned long long** factors:
int PrimeFactors (unsigned long long** factors, unsigned short int* size, unsigned long long n)
  1. 函数内部所有访问factors的地方,都要加上*解引用,操作原始指针指向的内存:

    • 调用realloc时(用临时变量存储结果,避免失败时丢失原始指针):
      unsigned long long* temp = realloc(*factors, (*size) * sizeof(unsigned long long));
      if (temp == NULL) {
          printf("realloc failed re-allocating factors array\n");
          return -1;
      }
      *factors = temp; // 更新原始指针
      printf("realloc() %d address in PrimeFactors() : %p\n", *size, (void *)&((*factors)[0]));
      
    • 赋值素因子时:
      (*factors)[factorsCount] = i;
      
    • 打印数组内容时:
      for(int i = 0; i < *size; ++i) printf("%llu\n", (*factors)[i]);
      
  2. 修改main函数里的调用,传入factors的地址:

PrimeFactors(&factors, size, n);

方法2:让函数返回新的指针地址

如果你不想用二级指针,可以修改函数的返回值类型,让它返回realloc后的新指针地址,main函数接收这个返回值来更新自己的指针。

修改步骤:

  1. 修改PrimeFactors的返回值类型,从int改成unsigned long long*,同时处理错误时返回NULL:
unsigned long long* PrimeFactors (unsigned long long* factors, unsigned short int* size, unsigned long long n) {
    printf("In PrimeFactors() :\n");
    *size = 2;
    unsigned long long* temp = realloc(factors, (*size) * sizeof(unsigned long long));
    if (temp == NULL) {
        printf("realloc failed re-allocating factors array\n");
        return NULL; // 返回NULL表示错误
    }
    factors = temp;
    printf("realloc() %d address in PrimeFactors() : %p\n", *size, (void *)&(factors[0]));

    // ... 其余逻辑保持不变,最后返回factors
    printf("Exiting PrimeFactors()...\n\n");
    return factors;
}
  1. main函数里接收返回值,并检查是否出错:
unsigned long long* new_factors = PrimeFactors(factors, size, n);
if (new_factors == NULL) {
    printf("PrimeFactors failed\n");
    free(factors);
    free(size);
    return -1;
}
factors = new_factors;

额外注意事项
  • 不管用哪种方法,都建议用临时变量存储realloc的结果,避免realloc失败时丢失原始指针(直接赋值的话,失败返回NULL会导致原来的内存地址丢失,造成内存泄漏)。
  • 你的代码中*size的初始值设为2,但实际素因子数量可能超过这个值,当前的逻辑是在factorsCount >= *size时扩容,这个逻辑是没问题的,但可以考虑初始值设得更合理(比如1,和main里的初始malloc保持一致)。

按照上面的方法修改后,main函数里的factors指针会正确更新为realloc后的新地址,你就能得到预期的输出结果了。

内容的提问来源于stack exchange,提问作者R2K

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:43:32