不能直接用int或long long做减法,因为几百位字符串远超其范围(约10¹⁸),必然溢出;须模拟手算逐位借位相减,并先提取绝对值、比较大小、处理符号,借位用carry变量向左传递。

为什么不能直接用 int 或 long long 做减法
因为输入字符串可能长达几百位,远超 long long 的最大值(约 10¹⁸),直接转数字会溢出或截断。比如 "999999999999999999999999" − "1",用内置类型根本存不下原数,更别说计算了。
所以必须模拟手算:从低位到高位逐位借位相减,结果存进新字符串。
如何处理负号和大小判断(避免结果为负)
大数减法本质是 |A| − |B|,但用户输入可能带负号,比如 "-123" − "456"。最稳妥的做法是先统一成非负数减法,再根据符号规则补结果符号。
实际编码中建议分三步走:
立即学习“C++免费学习笔记(深入)”;
- 用
std::string提取两个数的绝对值(去掉开头的'-'),并记录各自符号 - 比较绝对值大小:可用长度判断;等长时用字典序(
str1 > str2即可),决定谁减谁、结果正负 - 若被减数小于减数(如
"123" − "456"),交换后再算,最后给结果加'-'
注意:别用 stoi 或 stoll 判断大小——它们会抛 std::out_of_range 异常。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
核心减法逻辑:从右往左,借位怎么写才不漏
关键不是“怎么减”,而是“借位状态怎么传递”。常见错误是借位只影响下一位,但连续借位(如 "1000" − "1")需要一直传到左边第一个非零位。
推荐写法:用一个整型变量 carry 表示当前位是否需要借位(初始为 0),每轮先加上 carry(即上一轮借来的 −10),再算差值:
int digitA = (i >= 0) ? a[i] - '0' : 0;
int digitB = (j >= 0) ? b[j] - '0' : 0;
int diff = digitA - digitB - carry;
if (diff < 0) {
diff += 10;
carry = 1;
} else {
carry = 0;
}
result.push_back('0' + diff);
注意点:
-
i和j分别从两字符串末尾开始递减,短字符串补 0 - 结果是逆序的,最后要
std::reverse - 计算完要删前导零,但结果为
"0"时不能全删光——至少留一个'0'
边界情况:空串、全零、相同数相减
这些不是“特殊情况”,而是测试时最容易暴露逻辑漏洞的地方。
- 输入为空串?应提前返回错误或按约定视作
"0"(需文档说明) -
"000" − "0"→ 先去前导零变成"0" − "0",结果是"0" -
"123" − "123"→ 差全为 0,删完前导零只剩一个'0' - 如果减数比被减数长(如
"12" − "123"),前面已通过大小判断交换,不会进主循环出错
真正容易被忽略的是借位清零后,最后一轮仍可能产生额外位(如 "100" − "99" 得 "1",但循环结束时 carry 是 0,无需额外处理)——只要循环覆盖所有位(max(lenA, lenB)),就足够了。

















