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\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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM