前文链接:分数的加减法——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 ;           //运算符

  ;
}

总体结构


#define FAIL 0

int main( void )
{
  frac_t frc1 , frc2 ;//两个分数
  char op ;           //运算符

  while ( input_exp( &frc1 , &op , &frc2 ) != FAIL )//输入算式
  {
     //计算,输出
  }

  ;
}

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 )
{
    )
      return FAIL ;

    )
      return FAIL ;

   switch ( * p_o )
   {
      default : return FAIL ;//不是加、减法
      case '+':
      case '-':
                ;
   }

    )
      return FAIL ;

   return !FAIL ;
}

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

//计算,输出部分


  首先排除无意义的输入

      || frc2.denom ==  ) //无意义的输入
     {
        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 )//输入算式
  {
     //计算,输出
      || frc2.denom ==  ) //无意义的输入
     {
        puts( "分数无意义" );
        continue ;
     }

     switch ( op )
     {
        case '-':frc2.numer = - frc2.numer ;//把减法化为加法
        case '+':add_to( &frc1 , &frc2 );   //计算结果放在frc1中
                 break ;
     }

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

  ;
}

void output( frac_t fr )
{
    )
   {
      putchar( '-' );
      fr.numer = - fr.numer ;
   }

    )
   {
      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 ;

    ? 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 )
{
    )
      return FAIL ;

    )
      return FAIL ;

   switch ( * p_o )
   {
      default : return FAIL ;//不是加、减法
      case '+':
      case '-':
                ;
   }

    )
      return FAIL ;

   return !FAIL ;
}

分数的加减法——C语言初学者代码中的常见错误与瑕疵(12)的更多相关文章

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

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

  2. 一个超复杂的间接递归——C语言初学者代码中的常见错误与瑕疵(6)

    问题: 问题出处见 C语言初学者代码中的常见错误与瑕疵(5) . 在该文的最后,曾提到完成的代码还有进一步改进的余地.本文完成了这个改进.所以本文讨论的并不是初学者代码中的常见错误与瑕疵,而是对我自己 ...

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

    问题: 素数 在世博园某信息通信馆中,游客可利用手机等终端参与互动小游戏,与虚拟人物Kr. Kong 进行猜数比赛. 当屏幕出现一个整数X时,若你能比Kr. Kong更快的发出最接近它的素数答案,你将 ...

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

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

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

    见:C语言初学者代码中的常见错误与瑕疵(14) 相关链接:http://www.anycodex.com/blog/?p=87

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

    题目 字母的个数 现在给你一个由小写字母组成字符串,要你找出字符串中出现次数最多的字母,如果出现次数最多字母有多个那么输出最小的那个. 输入:第一行输入一个正整数T(0<T<25) 随后T ...

  7. 要心中有“数”——C语言初学者代码中的常见错误与瑕疵(8)

    在 C语言初学者代码中的常见错误与瑕疵(7) 中,我给出的重构代码中存在BUG.这个BUG是在飞鸟_Asuka网友指出“是不是时间复杂度比较大”,并说他“第一眼看到我就想把它当成一个数学问题来做”之后 ...

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

    问题: 矩形的个数 在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,2个2*2的矩形,2个3*1的矩形和1个3*2的矩形,总共18个矩形.给出A,B,计算可以从中找到 ...

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

    曾在豆瓣上看到过一个小朋友贴出他自己的代码(http://www.douban.com/group/topic/40293109/),当时随口指点了几句.难得这位小朋友虚心修正.从善如流,不断地改,又 ...

随机推荐

  1. NuGet -- 如何创建及发布自己的程序包

    STEP 1:在NuGet上注册并获取API Key    首先,你需要在NuGet(https://www.nuget.org/)上注册一个新的账号,然后在My Account页面,获取一个API ...

  2. jQuery--jqChart折线图使用eval处理返回数据无效的解决方法

    jquery初学者 查了很多帖子,jqchart插件做折线图时,处理返回数据时全都是eval,但我怎么也弄不出来,后来发现: 1.根本不需要eval处理,直接截取字符串即可(返回值要拼接好): 2.处 ...

  3. jsp里的逻辑语句c:if和c:choose

    1.c:if <c:if test=""></c:if> c:when的test里可以是变量或者是一个EL表达式,其结果应该是true或者false. EL ...

  4. 【Django】 视图层说明

    [Django视图层] 视图层的主要工作是衔接HTTP请求,Python程序和HTML模板,使他们能够有机互相合作从模型层lou到数据并且反馈.说到视图层的工作就有以下几个方面要说 ■ URL映射 对 ...

  5. 7.3.5 Tomcat堆溢出分析(1)

    实战Java虚拟机:JVM故障诊断与性能优化>第7章分析Java堆,本章主要介绍了Java堆的分析方法.首先,介绍了几种常见的Java内存溢出现象及解决思路.其次,探讨了java.lang.St ...

  6. LeetCode--025--k个一组翻转链表(java)

    给出一个链表,每 k 个节点一组进行翻转,并返回翻转后的链表. k 是一个正整数,它的值小于或等于链表的长度.如果节点总数不是 k 的整数倍,那么将最后剩余节点保持原有顺序. 示例 : 给定这个链表: ...

  7. 解决win10电脑VB虚拟机无法安装64位系统的方法

    64位电脑在VB虚拟机里却只能安装32位系统怎么办? **原因:CPU虚拟化未开启 只要CPU虚拟化开启即可解决问题. 开启步骤: 1.打开电脑设置 2.进入 更新和安全 界面 3.进入 恢复 界面 ...

  8. calico集成详解

    一.摘要 ======================================================================================= 包括三项: c ...

  9. bind系统调用

    /* * Bind a name to a socket. Nothing much to do here since it's * the protocol's responsibility to ...

  10. 新版SourceTree免帐号登录安装

    http://blog.csdn.net/zcbyzcb/article/details/72959720?locationNum=2&fps=1 [ { "$id": & ...