10:大整数加法
描述
求两个不超过200位的非负整数的和。
输入
有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。
输出
一行,即相加后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。
样例输入
22222222222222222222
33333333333333333333
样例输出
55555555555555555555
代码如下
#include<stdio.h>#include<string.h>void reverse(char str[],int n);//字符串反转函数void change(char str[],int n);//字符转数字函数int main(){char a[200]={0},b[200]={0};int r[201]={0};int n1,n2,i,max,f=0,k=0;//f用来判断相加结果有无前导0,赋值0表示默认有前导0scanf("%s",a);scanf("%s",b);n1=strlen(a);n2=strlen(b);reverse(a,n1);reverse(b,n2);change(a,n1);change(b,n2);max=(n1>n2)?n1:n2;for(i=0;i<max;i++)//求和过程{r[i]=(a[i]+b[i]+k)%10;k=(a[i]+b[i]+k)/10;//k表示每位数字求和产生的进位}r[i]=k;//要注意可能有最高位进位for(;i>=0;i--){if(f==0&&r[i]==0) continue;//判断结果有无前导0,有则跳过else f=1;//当f为1之后,遇到0就不会再跳过了printf("%d",r[i]);}if(f==0) printf("0");//如果结果就为0(即f的值未修改仍为0),那么输出0,}void reverse(char str[],int n){int i,t;for(i=0;i<n/2;i++){t=str[i];str[i]=str[n-i-1];str[n-i-1]=t;}}void change(char str[],int n){int i;for(i=0;i<n;i++) str[i]-=48;}
这道题做了蛮久,前前后后调试了很久。不过现在回想起来,其实很简单,关键仍是代码的思想。首先对于这类超长正数的加法,在我们人类计算看来与简单的加法其实本质是一样的,就是从个位开始,逐个位顺序相加,满十就进位。而题目为了干扰我们,输入的数据有些有前导0,但明白了计算过程就很简单。首先肯定是让两个数字都从最后一位开始计算,但是如果直接就这么处理,代码就会很复杂,至少看起来就会很头疼。
所以第一步的想法就是先把两个数字的高低位顺序调换,让低位在数组的前面,高位在后面。要注意这行代码for(i=0;i<n/2;i++)
i<n/2,循环次数是数组个数一半,因为每次交换是将数组中的两个元素进行位置交换。(对于奇数个元素的数组就是最中间元素不交换,其他元素进行交换)
然后就是两个数组从[0]开始按顺序相加就行。
接下来就是要思考如何相加,因为数组里存的是字符,而不是整数,所以在做加法时就不能想当然的按整数进行加法运算。这里我就先想到把字符转换成数字,也就是void change(char str[],int n);
函数的作用。每个元素减去0的ASCII码值(即48)就可以转换成数字。
最后一些步骤就看上面的代码就行了。
在这里我得到教训就是模块化编程的重要性,如果把所有代码都写在main函数里,检查代码的时候就会头皮发麻。如果把每个函数的功能都分出来,整体上就会很整洁,也方便阅读检查代码。