我的大数相加程序吐血编写历程

#include<stdio.h>
#include<string.h>
#define size 1001 
int main()
{
	char str1[size],str2[size],*num1,*num2,*p1,*p2;
	int ncase/*多组输入数目*/,mcase=1/*输出时的第几个输出计数器*/,up/*进位存储器*/,len1,len2,len;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%s %s",str1,str2);
		printf("Case %d:\n",mcase++);
		printf("%s + %s = ",str1,str2); 
		len1=strlen(str1);/*分别计算两数长度*/
		len2=strlen(str2);
		if( len1 >= len2 )/*把num1赋较大数的数组首地址num2赋较小数的数组首地址,且保证len1存长数组长度len2存短数组长度*/
		{
			num1=str1;
			num2=str2;
		}
		else
		{
			num1=str2;
			num2=str1;
			len=len1;
			len1=len2;
			len2=len;
		}
		up=0;/*进位赋初值0*/
		for(p1=num1+len1-1,p2=num2+len2-1;p1>=num1;p1--,p2--)/*从各自最小位逐位相加,以较大数的最高位为边界*/
		{								/********不顾越界的危险去操作*******/
			if( p2 < num2 )
				*p2=48;/*如果越界了则赋0值*/
			*p1=*p1+*p2-96+up;/*由ascII码值化为十进制值*/
			up=0;
			if( *p1 >= 10 )/*如果此位相加结果十进制值大于10则作减10处理*/
			{
				*p1-=10;
				up=1;/*进位寄存器赋1*/
			}
			*p1+=48;/*再次化为ascII码以供输出*/
		}
		if( up == 1 )
			printf("1");
		printf("%s\n",num1);/*输出经加法处理改动的大数组*/
		if( ncase != 0 ) 
			printf("\n");
	}
	return 0;
}

上面的代码是我刚开始的版本。我为了省心省力,对越界的部分进行了操作,在数组边界前的内存赋0。几乎可以保证跑出来的所有结果都是正确的。(毕竟人不是机器,一些极为边界的值是无法测试到的)结果在oj上的结果是OLE。我一直很困惑,因为自己用电脑跑了几组都没问题。而且看上去也很完美没有什么十分明显的致命错误。
后来咨询了acm老队员。终于弄清楚了原因所在。因为对数组越界之后的内存进行了操作。事实上这块内存是未知的位置,可能非常幸运的是空的内存可以毫无问题的使用,但事实上极有可能操作的就是较大数组的内容。而因为数组太大了,测试数据很难反映出这个问题,大数组的最后几个单元已经被读取过了。当大数组里的值是一个1000位的数时,或许最后的输出就能显示出错误。
总之得到的教训和经验就是不要随意操作没有申请的内存空间。
下面是修改之后的结果。终于可以完美运行并ac了。

#include<stdio.h>
#include<string.h>
#define size 1001 
int main()
{
	char str1[size],str2[size],*num1,*num2,*p1,*p2;
	int ncase/*多组输入数目*/,mcase=1/*输出时的第几个输出计数器*/,up/*进位存储器*/,len1,len2,len;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%s %s",str1,str2);
		printf("Case %d:\n",mcase++);
		printf("%s + %s = ",str1,str2); 
		len1=strlen(str1);/*分别计算两数长度*/
		len2=strlen(str2);
		if( len1 >= len2 )/*把num1赋较大数的数组首地址num2赋较小数的数组首地址,且保证len1存长数组长度len2存短数组长度*/
		{
			num1=str1;
			num2=str2;
		}
		else
		{
			num1=str2;
			num2=str1;
			len=len1;
			len1=len2;
			len2=len;
		}
		up=0;/*进位赋初值0*/
		for(p1=num1+len1-1,p2=num2+len2-1;p2>=num2;p1--,p2--)/*从各自最小位逐位相加,以较小数的最高位为边界*/
		{
			*p1=*p1+*p2-96+up;/*由ascII码值化为十进制值*/
			up=0;
			if( *p1 >= 10 )/*如果此位相加结果十进制值大于10则作减10处理*/
			{
				*p1-=10;
				up=1;/*进位寄存器赋1*/
			}
			*p1+=48;/*再次化为ascII码以供输出*/
		}
		for(;p1>=num1;p1--)
		{
			*p1=*p1-48+up;/*由ascII码值化为十进制值*/
			up=0;
			if( *p1 >= 10 )/*如果此位相加结果十进制值大于10则作减10处理*/
			{
				*p1-=10;
				up=1;/*进位寄存器赋1*/
			}
			*p1+=48;/*再次化为ascII码以供输出*/
		} 
		if( up == 1 )
			printf("1");
		printf("%s\n",num1);/*输出经加法处理改动的大数组*/
		if( ncase != 0 ) 
			printf("\n");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值