分数的加减法——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( '
' );

完整的代码:


/*
分数的加减法 
编写一个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( '
' );
  }

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