zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    PostgreSQL查看等待锁的SQL和进程
    effective_io_concurrency很重要的一个参数
    PostgreSQL逻辑复制到kafka-实践
    Linux下路由配置梳理(转)
    创建B树,动态添加节点,并使用三种遍历算法对树进行遍历
    思考--PostgreSQL在与mysql的比较中稍微弱势项
    思考-继续思考在数据库中两个表join的问题
    思考--mysql 分库分表的思考
    超级实用的网址大全
    C++ 读取txt文本内容,并将结果保存到新文本
  • 原文地址:https://www.cnblogs.com/pmer/p/3428526.html
Copyright © 2011-2022 走看看