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

计算大整数的程序中Realloc偶发栈溢出问题排查

问题分析与修复方案

1. 内存分配体系混用(核心偶发错误原因)

代码里混合使用了C++的new[]和C语言的realloc/free,这属于未定义行为:

  • 所有构造函数均使用new char[]分配digits内存
  • Sub函数却用realloc重新分配该指针指向的内存

realloc仅能操作malloc/calloc/realloc分配的内存,用它处理new分配的内存会直接破坏堆结构,导致偶发栈溢出、崩溃等不可预测的错误。

修复方法:
统一使用C++内存管理方式,替换realloc为new[]+内存拷贝:

if (this->length < index) {
    char* tmp = new char[index + 1];
    if (tmp == nullptr) {
        cerr << "Memory reallocation failed, the program will terminate." << endl;
        delete[] this->digits;
        exit(0);
    }
    // 拷贝原有数据
    strcpy(tmp, this->digits);
    // 释放旧内存
    delete[] this->digits;
    this->digits = tmp;
    
    this->length = index;                   
    this->digits[this->length] = '\0';  
}

2. 递归调用触发栈溢出

Sub函数借位时递归调用自身,当连续借位深度过大(比如10000位超大整数减1),会耗尽栈空间触发栈溢出。这种错误的出现频率取决于借位深度,因此表现为偶发。

修复方法:
将递归改为循环实现,避免栈溢出:

// 替换原递归逻辑
int borrow = num - '0';
int current_idx = index - 1;
while (borrow > 0 && current_idx >= 0) {
    int digit = this->digits[current_idx] - '0';
    digit -= borrow;
    if (digit < 0) {
        digit += 10;
        borrow = 1;
    } else {
        borrow = 0;
    }
    this->digits[current_idx] = digit + '0';
    current_idx--;
}
// 若借位未清0,扩展位数处理
if (borrow > 0) {
    char* tmp = new char[this->length + 2];
    strcpy(tmp + 1, this->digits);
    tmp[0] = '9';
    delete[] this->digits;
    this->digits = tmp;
    this->length += 1;
    this->digits[this->length] = '\0';
}

同时注意原代码的计算错误:this->digits[index - 1] -= num + '0';会导致数值溢出,正确写法应为this->digits[index - 1] -= (num - '0');,因为要减去的是num对应的数值而非字符ASCII值之和。

3. 构造函数的placement new风险

inf_int(int n)中,当i=0(即n=0)时使用new (this) inf_int();重新构造对象,会引发:

  • 若对象已分配内存,直接造成内存泄漏
  • 二次调用构造函数触发未定义行为

修复方法:
直接初始化成员变量,摒弃placement new:

if (i == 0) {   
    this->digits = new char[2]; 
    this->digits[0] = '0';       
    this->digits[1] = '\0';
    this->length = 1;
    this->thesign = true;
}

4. 字符串处理的内存越界

inf_int(const char* str)构造函数存在多处越界:

  • char* answer = new char[strlen(str)];未给字符串结束符'\0'留空间,strcpy(answer, str)会越界写入
  • 处理负号时char* solution = new char[strlen(str)];,后续solution[strlen(str)] = '\0';的索引超出数组范围

修复方法:
修正内存分配大小:

// 修正answer的分配
char* answer = new char[strlen(str) + 1];
// 处理负号时的solution分配
size_t num_len = strlen(str) - 1;
char* solution = new char[num_len + 1];

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 15:05:32