问题
小学生数学
很多小学生在学习加法时,发现“进位”特别容易出错。你的任务是计算两个数在相加时需要多少次进位。你编制的程序应当可以连续处理多组数据,直到读到两个0(这是输入结束标记)。样例:
输入
123 456
555 555
123 594
0 0输出:
0
3
1
原代码:
1 #include <stdio.h>
2 #include <math.h>
3 int Take_number(int x,int y) //定义函数取整数X的第Y位
4 { 5 int temp; 6 if(x==0) 7 { 8 printf("wrong number\n"); 9 return 0; 10 } 11
12 temp=(int)pow(10,y-1); 13 temp=x/temp; 14 return temp%10; 15 } 16
17 int count(int x) //定义函数取位数
18 { 19 int i,carry,count; 20 for(i=0,count=1;;i++) 21 { 22 carry=(int)pow(10,i); 23 if(x/carry==0) 24 break; 25 else count++; 26 } 27 return count; 28 } 29
30 int main() 31 { 32 int a[100],temp,i,j,carry[10]; 33 int Take_number(int x,int y); 34 int count(int x); 35 printf("plese input the number and end with 0 0\n"); 36
37 for(i=1;;i+=2) //输入相应数值
38 { 39 scanf("%d%d",&a[i-1],&a[i]); 40 if(a[i-1]==0 && a[i]==0) 41 break; 42 } 43
44 for(i=1;a[i-1]!=0;i+=2) 45 { 46 for(j=1,temp=0;j<=(a[i-1]>a[i]?count(a[i-1]):count(a[i]));j++) 47 { 48 carry[j]=0; 49 if(carry[j-1]) //若前一位有进位,该位相加为9也有进位
50 if(Take_number(a[i-1],j)+Take_number(a[i],j)>=9) 51 carry[j]=1; 52 else
53 carry[j]=0; 54 else
55 if(Take_number(a[i-1],j)+Take_number(a[i],j)>=10) //若前一位无进位,相加为10才有进位
56 carry[j]=1; 57 else ; 58 if(carry[j]) 59 temp=temp+1; 60 else ; 61 } 62 printf("%d\n",temp); 63 } 64
65 return 0; 66 }
评析:
题目比较有趣,但代码乏善可陈。
int a[100],temp,i,j,carry[10];
还是变量定义太多,并不必要地使用了数组这种复杂的数据结构,表明作者缺乏大局观,对代码的整体设计错误。其实这里只需要两个变量就足够了,就是存储要做加法的那两个数。题目在这里也有欠严密,没提这两个数应该是正整数。如果是允许输入负整数或者输入小数,那就完全是另一道题了。
用int [100]这种类型存储输入数据显然是错误的,因为这最多可以存储50对数据,再多就出错了。所以
printf("plese input the number and end with 0 0\n"); for(i=1;;i+=2) //输入相应数值
{ scanf("%d%d",&a[i-1],&a[i]); if(a[i-1]==0 && a[i]==0) break; }
显然是错误的。只能采用输入一组数据就处理一组数据的方案。例如象下面这样写:
int addend1,addend2; while (scanf("%d%d",&addend1,&addend2),addend1!=0 || addend2!=0 ) { //处理addend1,addend2
}
int Take_number(int x,int y); int count(int x);
这个有些莫名其妙。把函数定义写在了前面,却又在main()中又写了函数类型声明,画蛇添足。应该把函数类型声明写在main()之外、之前,把函数定义放在main()后面。
for(i=1;a[i-1]!=0;i+=2) { for(j=1,temp=0;j<=(a[i-1]>a[i]?count(a[i-1]):count(a[i]));j++) { carry[j]=0; if(carry[j-1]) //若前一位有进位,该位相加为9也有进位
if(Take_number(a[i-1],j)+Take_number(a[i],j)>=9) carry[j]=1; else carry[j]=0; else
if(Take_number(a[i-1],j)+Take_number(a[i],j)>=10) //若前一位无进位,相加为10才有进位
carry[j]=1; else ; if(carry[j]) temp=temp+1; else ; } printf("%d\n",temp); }
这个从结构上来说就不合理,main()中的代码写得太多太细了。从代码逻辑上看有几个明显的错误,就是在内层循环中的
if(carry[j-1])
注意循环变量j的初值为1,而carry是一个没有初始化的局部auto数组,因此当j为1时carry[j-1]即carry[0]是垃圾值,所以这个if选择没有意义。显而易见,后面所有代码都是错误的。所以就不进一步分析了。
重构:
1 /*
2 题目:小学生数学 3 很多小学生在学习加法时,发现“进位”特别容易出错。 4 你的任务是计算两个非负整数在相加时需要多少次进位。 5 你编制的程序应当可以连续处理多组数据,直到读到两个0(这是输入结束标记)。 6 样例:输入 7 123 456 8 555 555 9 123 594 10 0 0 11 输出: 12 0 13 3 14 1 15
16 作者:薛非 17 出处:http://www.cnblogs.com/pmer/p/3428526.html 18 */
19
20 #include <stdio.h>
21
22 unsigned get_carry_times ( unsigned , unsigned ); 23
24 int main( void ) 25 { 26 unsigned addend1,addend2 ; 27
28 while ( puts("输入两个非负整数,0 0表示结束"), 29 scanf("%u%u",&addend1,&addend2), 30 addend1!=0u || addend2!=0u ) 31 { 32 printf("%u\n", get_carry_times ( addend1 , addend2 ) ); 33 } 34
35 return 0; 36 } 37
38 unsigned get_carry_times ( unsigned a1 , unsigned a2 ) 39 { 40 unsigned c_t = 0u ;//进位次数
41 unsigned c = 0u ;//进位
42
43 do
44 { 45 c += a1 % 10u + a2 % 10u ; 46
47 if ( (c /= 10u) != 0u ) 48 c_t ++ ; 49
50 a1 /= 10u ; 51 a2 /= 10u ; 52 } 53 while ( a1 + a2 != 0u ); 54
55 return c_t ; 56 }
