分數的加減法——C語言初學者代碼中的常見錯誤與瑕疵(12)


 前文鏈接:分數的加減法——C語言初學者代碼中的常見錯誤與瑕疵(11)

重構

題目的修正 


  我拋棄了原題中“其中a, b, c, d是一個0-9的整數”這樣的前提條件,因為這種限制毫無必要。只假設a, b, c, d是十進制整數形式的字符序列。

  我也不清楚這種題目應該如何結束輸入。下面的代碼假設在沒有正確輸入完整的運算式時結束。

數據結構 


typedef
   struct 
   {
      int numer ; //分子
      int denom ; //分母
   }
frac_t ;//分數類型

 數據 


  一共需要三個變量,兩個記錄分數,一個記錄運算符。

#include <stdio.h>

int main( void )
{
  frac_t frc1 , frc2 ;//兩個操作數
  char op ;           //運算符
  
  return 0;
}

總體結構


#define FAIL 0

int main( void )
{
  frac_t frc1 , frc2 ;//兩個分數
  char op ;           //運算符
  
  while ( input_exp( &frc1 , &op , &frc2 ) != FAIL )//輸入算式 
  {
     //計算,輸出 
  }

  return 0;
}

input_exp()的實現


int input_exp( frac_t * , char * , frac_t * ); 
int input_frac( frac_t * );

int input_exp( frac_t * p_f1 , char * p_o , frac_t * p_f2 )
{
   if ( input_frac( p_f1 ) != 2 )
      return FAIL ;
    
   if ( scanf(" %c" , p_o ) != 1 )//if ( scanf(" %c " , p_o ) != 1 )
      return FAIL ;
   
   switch ( * p_o )
   {
      default : return FAIL ;//不是加、減法
      case '+':
      case '-':
                ;
   }

   if ( input_frac( p_f2 ) != 2 )
      return FAIL ;

   return !FAIL ;
}

int input_frac( frac_t * p_f )
{
   return scanf("%d / %d" , &p_f->numer , &p_f->denom );
}

//計算,輸出部分


  首先排除無意義的輸入  

     if ( frc1.denom == 0 || frc2.denom == 0 ) //無意義的輸入 
     {
        puts( "分數無意義" );
        continue ;
     }

  把減法變為加法

     switch ( op )
     {
        case '-':frc2.numer = - frc2.numer ;//把減法化為加法 
        case '+':add_to( &frc1 , &frc2 );   //計算結果放在frc1中 
                 break ;
     }

  最后輸出結果

     output( frc1 );
     putchar( '\n' );

完整的代碼:


/*
分數的加減法 
編寫一個C程序,實現兩個分數的加減法 
輸入:輸入包含多行數據 
每行數據的格式是 a/boc/d 。 
其中a, b, c, d為十進制整數,o是運算符"+"或者"-"。 
輸出:對於輸入數據的每一行輸出兩個分數的運算結果。 
注意結果應符合書寫習慣,沒有多余的符號、分子、分母,並且化簡至最簡分數 

樣例輸入: 
1/8+3/8 
1/4-1/2 
1/3-1/3 
輸出: 
1/2 
-1/4 
0

作者:薛非
出處:http://www.cnblogs.com/pmer/   “C語言初學者代碼中的常見錯誤與瑕疵”系列博文

*/


#include <stdio.h>
#include <stdlib.h>

typedef
   struct 
   {
      int numer ; //分子
      int denom ; //分母
   }
frac_t ;//分數類型

#define FAIL 0

int input_exp( frac_t * , char * , frac_t * ); 
int input_frac( frac_t * );
void add_to( frac_t * , frac_t const * );
int find_lcm( int , int );
int find_gcd( int , int );
void reduce( frac_t * );
void output( frac_t );

int main( void )
{
  frac_t frc1 , frc2 ;//兩個分數
  char op ;           //運算符
  
  while ( input_exp( &frc1 , &op , &frc2 ) != FAIL )//輸入算式 
  {
     //計算,輸出 
     if ( frc1.denom == 0 || frc2.denom == 0 ) //無意義的輸入 
     {
        puts( "分數無意義" );
        continue ;
     }
     
     switch ( op )
     {
        case '-':frc2.numer = - frc2.numer ;//把減法化為加法 
        case '+':add_to( &frc1 , &frc2 );   //計算結果放在frc1中 
                 break ;
     }
     
     output( frc1 );
     putchar( '\n' );
  }

  return 0;
}

void output( frac_t fr )
{
   if ( fr.numer < 0 )
   {
      putchar( '-' );
      fr.numer = - fr.numer ; 
   }
   
   if ( fr.denom == 1 )
   {
      printf( "%d" , fr.numer );
      return ;
   }
   
   printf( "%d/%d" , fr.numer , fr.denom );
}

void reduce( frac_t * p_f )
{
   int gcd = find_gcd( abs( p_f->numer ) , abs( p_f->denom ) ) ; 
             
   p_f->denom /= gcd ;
   p_f->numer /= gcd ;
}

int find_gcd( int m , int n )
{
   int t ;
   
   return (t = m % n) == 0 ? n : find_gcd( n , t );
}

int find_lcm( int m , int n )
{
   return m / find_gcd( m , n ) * n ; 
}

void add_to( frac_t * p_f1 , frac_t const * p_f2 )
{
   int lcm = find_lcm( abs( p_f1->denom ) , abs( p_f2->denom ) );
   
   p_f1->numer = lcm / p_f1->denom * p_f1->numer 
               + lcm / p_f2->denom * p_f2->numer ;
   p_f1->denom = lcm ;   //分母總是正的 
   
   reduce( p_f1 );       //約分           
}

int input_frac( frac_t * p_f )
{
   return scanf( "%d / %d" , &p_f->numer , &p_f->denom );
}

int input_exp( frac_t * p_f1 , char * p_o , frac_t * p_f2 )
{
   if ( input_frac( p_f1 ) != 2 )
      return FAIL ;
    
   if ( scanf(" %c" , p_o ) != 1 )//if ( scanf( " %c " , p_o ) != 1 )
      return FAIL ;
   
   switch ( * p_o )
   {
      default : return FAIL ;//不是加、減法 
      case '+':
      case '-': 
                ;
   }

   if ( input_frac( p_f2 ) != 2 )
      return FAIL ;

   return !FAIL ;
}

 


免責聲明!

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



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