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

总体结构


#define FAIL 0

int main( void )
{
frac_t frc1 , frc2 ;//两个分数
char op ; //运算符 while ( input_exp( &frc1 , &op , &frc2 ) != FAIL )//输入算式
{
//计算,输出
} return ;
}

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 ) != )
return FAIL ; if ( scanf(" %c" , p_o ) != )//if ( scanf(" %c " , p_o ) != )
return FAIL ; switch ( * p_o )
{
default : return FAIL ;//不是加、减法
case '+':
case '-':
;
} if ( input_frac( p_f2 ) != )
return FAIL ; return !FAIL ;
} int input_frac( frac_t * p_f )
{
return scanf("%d / %d" , &p_f->numer , &p_f->denom );
}

//计算,输出部分


  首先排除无意义的输入

     if ( frc1.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 )//输入算式
{
//计算,输出
if ( frc1.denom == || frc2.denom == ) //无意义的输入
{
puts( "分数无意义" );
continue ;
} switch ( op )
{
case '-':frc2.numer = - frc2.numer ;//把减法化为加法
case '+':add_to( &frc1 , &frc2 ); //计算结果放在frc1中
break ;
} output( frc1 );
putchar( '\n' );
} return ;
} void output( frac_t fr )
{
if ( fr.numer < )
{
putchar( '-' );
fr.numer = - fr.numer ;
} if ( fr.denom == )
{
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) == ? 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 ) != )
return FAIL ; if ( scanf(" %c" , p_o ) != )//if ( scanf( " %c " , p_o ) != )
return FAIL ; switch ( * p_o )
{
default : return FAIL ;//不是加、减法
case '+':
case '-':
;
} if ( input_frac( p_f2 ) != )
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. Android模拟器disconnected问题

    具体原因不明,偶尔会出现 window -> Show Views -> device -> view menu -> Reset adb  一般可以解决该问题

  2. jquery在线手册

    开发时用到jquery,有几个函数想不起来怎么用,找了一下jquery在线手册. 记录一下,下回有需要再看看. 链接:http://www.chenfahui.cn/jq/

  3. saltstack故障解决

    [root@saltstack_s ~]# salt '*' test.pingSalt request timed out. The master is not responding. If thi ...

  4. Access 2003版数据库在Win7 64位系统下的不适应

    使用ODBC连接不适应 使用microsoft.jet.4.0链接会出现“未在本地计算机上注册microsoft.jet.4.0” 应使用 Provider=Microsoft.ACE.OLEDB.1 ...

  5. shell eval用法

    转自:http://blog.csdn.net/w_ww_w/article/details/7075867 eval可读取一连串的参数,然后再依参数本身的特性来执行.eval是shell内建命令,可 ...

  6. python_序列

    1. python存在6中内建序列:列表.元组.字符串.Unicode字符串.buffer对象.xrange对象 列表可以修改,元组和字符串不可以修改. 2. 序列支持的操作: 索引 序列中所有的元素 ...

  7. 堡垒机 paramiko 自动登陆代码

    #!/usr/bin/env python # Copyright (C) - Robey Pointer <robeypointer@gmail.com> # # This file i ...

  8. iOS面试必看,最全梳理

    序言 目前形势,参加到iOS队伍的人是越来越多,甚至已经到供过于求了.今年,找过工作人可能会更深刻地体会到今年的就业形势不容乐观,加之,培训机构一火车地向用人单位输送iOS开发人员,打破了生态圈的动态 ...

  9. ios-通知简单示例

    通知是一种一对多的信息广播机制,一个应用程序同时只能有一个NSNotificationCenter(通知中心)对象,用来添加通知观察者或者说监听者,以及发送通知. 用的地方是:不同控制器的传值回调.d ...

  10. snapshot standby database

    快照备库接收和归档主库发送来的redo,但是不会应用:切换成physical standby之后会自动开启redo apply.快照standby不可以参加主备切换:在最大保护性模式下,如果只有一个备 ...