zoukankan      html  css  js  c++  java
  • 分数的加减法——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 ;
    }
  • 相关阅读:
    caffe for python (官方翻译)
    实验三、页式地址重定位模拟
    实验二、银行家算法
    实验一:进程调度实验
    植物大战僵尸作弊器源代码(MFC版)
    植物大战僵尸作弊器源代码(控制台版)
    CE寻找游戏基址
    植物大战僵尸内存地址(转)
    Detour的简单使用
    C/S模型之命名管道
  • 原文地址:https://www.cnblogs.com/pmer/p/3486631.html
Copyright © 2011-2022 走看看