C语言初学者代码中的常见错误与瑕疵(4)

问题


小学生数学
很多小学生在学习加法时,发现“进位”特别容易出错。你的任务是计算两个数在相加时需要多少次进位。你编制的程序应当可以连续处理多组数据,直到读到两个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
");
 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
");
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
",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
");

 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
",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
", 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 }
原文地址:https://www.cnblogs.com/pmer/p/3428526.html