不能直接用int或long long做大数加法,因为其位数上限分别为约10位和19位,超长数字会溢出;必须将数字作为字符串,从末尾逐位模拟手算加法,维护进位并反转结果。

为什么不能直接用 int 或 long long 做大数加法
因为 C++ 内置整型有上限:int 通常最多表示 10 位十进制数,long long 也只到约 19 位。一旦输入超过这个长度(比如 50 位的字符串数字),直接转换会溢出或截断,结果完全不可信。
所以必须绕过内置类型,把数字当字符串处理,一位一位模拟手算加法。
- 输入一定是非负整数字符串(如
"12345678901234567890"),不含前导空格或符号 - 要从最低位(字符串末尾)开始逐位相加,维护进位
carry - 结果需逆序拼接——手算是从右往左写,但字符串拼接习惯从左往右,所以最后要反转
如何用 string 模拟加法并正确处理进位
核心是双指针从两个字符串末尾向前扫描,每次取当前位数字(用 s[i] - '0' 转成整数),加上进位,再对 10 取模得当前结果位,除以 10 更新进位。
注意边界:当一个字符串已扫完,另一个还剩时,不能跳过,仍要继续加进位和剩余位。
立即学习“C++免费学习笔记(深入)”;
string addStrings(string num1, string num2) {
string res;
int i = num1.size() - 1, j = num2.size() - 1, carry = 0;
while (i >= 0 || j >= 0 || carry) {
int x = (i >= 0) ? num1[i--] - '0' : 0;
int y = (j >= 0) ? num2[j--] - '0' : 0;
int sum = x + y + carry;
res.push_back('0' + sum % 10);
carry = sum / 10;
}
reverse(res.begin(), res.end());
return res;
}-
i >= 0和j >= 0必须显式判断,否则访问num1[-1]是未定义行为 -
carry单独作为循环条件,是为了处理最后还有进位的情况(如"99" + "1"得"100") - 不要用
res = char(...) + res拼接,那是 O(n²);用push_back+reverse是 O(n)
如果输入含前导零或需要支持负数怎么办
标准大数加法题默认输入合法、无符号、无前导零。但实际读文件或用户输入可能不守规矩。
前导零不影响算法逻辑("00123" 和 "123" 算出来一样),但输出不应带前导零——除非结果就是 "0"。
- 可在返回前去掉前导零:
res.erase(0, res.find_first_not_of('0')); if (res.empty()) res = "0"; - 负数需额外判断符号位,拆成「同号相加」或「异号相减」,本质是调用加法或减法函数,复杂度翻倍,一般题目会明确说明“非负”
- 若真要支持负数,别硬改加法函数,应先解析符号,再分情况调用
addStrings或自定义的subStrings
性能与边界容易被忽略的点
看起来只是遍历一遍字符串,时间复杂度 O(max(m,n)),但有几个隐性开销常被低估:
-
string::push_back在容量不足时会触发内存重分配,建议初始化res容量:res.reserve(max(m,n) + 1); -
reverse是必要开销,无法避免;想省掉它就得用insert(res.begin(), ...),但那是 O(n²),更慢 - 如果反复调用该函数(比如在高精度乘法中做多次加法),考虑复用
string对象、避免频繁构造析构 - 输入为空字符串?虽然题设通常不考虑,但健壮实现应先检查:
if (num1.empty()) return num2;等
真正难的不是写对逻辑,而是想到所有输入变异场景,并在不破坏简洁性的前提下守住边界。


















