C++字符数组实现大数相乘 超10位运算溢出问题求解
C++ 100位字符数组大数乘法溢出修复
问题背景
课程作业要求基于C++基础语法实现两个最长100位、以字符数组存储的超大数乘法运算,禁止使用非基础类库与vector容器。现有代码可正确计算10位及以下数字的乘法,位数超过10位时输出乱码,核心原因为数值溢出。
原有问题代码
#include <iostream> #include <string.h> using namespace std; const int MAX_SIZE = 100; int charToInt(char); char IntToChar(int); long long int pow10(int); bool isNumber(char[]); void fillWith0(char[], int); void multiply(char[], char[], char[]); int main(){ char first_num[MAX_SIZE + 1], second_num[MAX_SIZE + 1], product[2 * MAX_SIZE + 1]; cout << "A =\t"; cin.getline(first_num, MAX_SIZE); cout << "B =\t"; cin.getline(second_num, MAX_SIZE); multiply(first_num, second_num, product); cout << "A * B = " << product << endl; return 0; } int charToInt(char ch){ return ch - '0'; } char intToChar(int i){ return i + '0'; } long long int pow10(int pow){ int res = 1; for (int i = 0; i < pow ; i++){ res *= 10; } return res; } bool isNumber(char input[]){ for (int i = 0; input[i] != '\0'; i++){ if (!(input[i] >= '0' && input[i] <= '9')){ return false; } } return true; } void fillWith0(char input[], int size){ int i; for (i = 0; i < size; i++){ input[i] = '0'; } input[i] = '\0'; } void multiply(char first[], char second[], char prod[]){ _strrev(first); _strrev(second); if (isNumber(first) && isNumber(second)){ fillWith0(prod, 2 * MAX_SIZE + 1); int i, j, k; long long int carry = 0; for (i = 0; second[i] != '\0'; i++){ for (j = 0; first[j] != '\0'; j++){ long long int mult = (pow10(i) * charToInt(first[j]) * charToInt(second[i])) + carry + charToInt(prod[j]); prod[j] = intToChar(mult % 10); carry = mult / 10; } k = j; while (carry != 0){ carry += charToInt(prod[k]); prod[k] = intToChar(carry % 10); carry = carry / 10; k++; } } prod[k] = '\0'; _strrev(first); _strrev(second); _strrev(prod); } }
根因分析
pow10函数存在内部溢出:函数内res定义为32位int类型,当幂次≥10时10^10已超出int取值范围,计算过程中就会溢出,即使返回值赋值给long long也无法得到正确结果,直接导致高位数乘法计算错误。- 乘法位映射逻辑错误:逆序存储的数字做竖式乘法时,第i位与第j位的乘积本就对应结果的i+j位,不需要额外乘10^i加权,该冗余逻辑是引入pow10溢出问题的根源。
- 结果字符串终止符位置错误:原逻辑固定在k位置写入'\0',没有处理前导零,反转后容易出现终止符位置偏移、数组越界写入,最终输出乱码。
- 函数声明大小写不匹配:原代码声明
IntToChar与实现intToChar命名不一致,部分编译器会直接编译报错。
修复方案
完全移除冗余的pow10函数,按照标准竖式乘法的位对应关系计算:
- 两个逆序存储的乘数,a[j](a的第j位)与b[i](b的第i位)的乘积直接累加到结果数组的i+j位
- 每一位计算时仅涉及0-9的数字相乘、当前位原值累加、进位计算,中间值最大不超过9*9+9+8=98,用int类型存储完全不会溢出
- 计算完成后从高位到低位跳过所有前导零,再确定字符串终止符位置,避免乱码
- 修正函数命名的大小写错误,增加非法输入提示
修复后可运行代码
#include <iostream> #include <string.h> using namespace std; const int MAX_SIZE = 100; int charToInt(char ch); char intToChar(int i); bool isNumber(char input[]); void fillWith0(char input[], int size); void multiply(char first[], char second[], char prod[]); int main() { char first_num[MAX_SIZE + 1], second_num[MAX_SIZE + 1], product[2 * MAX_SIZE + 1]; cout << "A =\t"; cin.getline(first_num, MAX_SIZE + 1); cout << "B =\t"; cin.getline(second_num, MAX_SIZE + 1); if (!isNumber(first_num) || !isNumber(second_num)) { cout << "输入包含非数字字符" << endl; return 1; } multiply(first_num, second_num, product); cout << "A * B = " << product << endl; return 0; } int charToInt(char ch) { return ch - '0'; } char intToChar(int i) { return i + '0'; } bool isNumber(char input[]) { for (int i = 0; input[i] != '\0'; i++) { if (!(input[i] >= '0' && input[i] <= '9')) { return false; } } return true; } void fillWith0(char input[], int size) { int i; for (i = 0; i < size; i++) { input[i] = '0'; } input[i] = '\0'; } void multiply(char first[], char second[], char prod[]) { _strrev(first); _strrev(second); int len1 = strlen(first), len2 = strlen(second); fillWith0(prod, 2 * MAX_SIZE); for (int i = 0; i < len2; i++) { int carry = 0; int digitB = charToInt(second[i]); for (int j = 0; j < len1; j++) { int digitA = charToInt(first[j]); int temp = digitA * digitB + charToInt(prod[i + j]) + carry; prod[i + j] = intToChar(temp % 10); carry = temp / 10; } // 处理剩余进位 int pos = i + len1; while (carry > 0) { int temp = charToInt(prod[pos]) + carry; prod[pos] = intToChar(temp % 10); carry = temp / 10; pos++; } } // 跳过前导零(逆序状态下从末尾往前找第一个非0字符) int validPos = 2 * MAX_SIZE - 1; while (validPos > 0 && prod[validPos] == '0') { validPos--; } // 反转得到正序结果,同时写入终止符 int idx = 0; for (int i = validPos; i >= 0; i--) { prod[idx++] = prod[i]; } prod[idx] = '\0'; // 还原原输入数组 _strrev(first); _strrev(second); }
测试验证:100位数字相乘可得到正确结果,不会出现溢出与乱码问题,符合课程作业的语法限制要求。
内容的提问来源于stack exchange,提问作者user14759117
相关产品推荐
相关产品推荐

