zoukankan      html  css  js  c++  java
  • 自制简单计算器

    导言

    好多次想学习C++,但都是望而却步。这次因为专业方向原因(数字图像处理),不得不走上学习C++的道路上。网上找了些C++的推荐书籍,入门的大多都是《C++程序设计语言》、《C++ primer》,《C++ primer plus》。这3本书都找来看,但是都没有看完,都是看到类型部分就放弃了。网上推荐的看不了,就自个在图书馆寻寻觅觅,偶然找到了《C++ In Action 》,大致翻看了下,没有用几章介绍类型,就它了。新学期第一周,把第一部分语言的基础看完了,这里就着书中计算器的例子做个总结。

     

    简单计算器

    计算器基于堆栈,接受用户数字和运算符号的输入。输入数字则保存在栈中,如果是运算符号则弹出栈中数字进行运算。计算器实现的是后缀表达式(posfix notation)的运算,不需要小括号输入。

    计算器的顶级对象当然是计算器本身,保存输入的数字并进行运算。输入的数字需要保存在栈中,并且每次运算完成后需要遍历栈中元素,所以需要一个栈及栈的访问器。另外用于的输入独立于计算器,这就需要一个输入对象获取用户的输入。

    栈及其访问器

    栈的实现是基于数组的。其定义如下:

       1:  const int maxStack = 16 ;
       2:   
       3:  class LStack
       4:  {
       5:      //访问器作为友元,可以访问类的私有成员
       6:      friend class LStackSeq ;
       7:  public:
       8:      LStack()
       9:          :top(0) {}
      10:   
      11:      int Pop();
      12:      void Push(int i);
      13:      bool IsFull() ;
      14:      bool IeEmpty() ;
      15:  private:
      16:      int top ;
      17:      int arr[maxStack] ;
      18:  };

    利用数组arr保存栈中元素,成员top作为指向栈顶的指针。其实现代码还是很简单的,这里就不贴出具体代码了。

    访问器逐个返回栈中的元素,需要访问栈的私有成员,作为栈的友元出现。其定义:

       1:  class LStackSeq
       2:  {
       3:  public:
       4:      LStackSeq(LStack const & stack) ;
       5:      bool AtEnd() const ; //是否完成
       6:      void Advance() ; //移动到下一项
       7:      int GetNum() const ;//当前项
       8:  private:
       9:      int iCur ;
      10:      LStack const & stack ;
      11:  };

    iCur指向当前访问的元素,Advance用来移动iCur实现元素遍历,AtEnd判断是否遍历完了,GetNum取得当前元素的值。

    实现了访问器后,对栈中元素的遍历就很方便了。

       1:      for(LStackSeq seq(stack) ; !seq.AtEnd() ; seq.Advance())
       2:          std::cout << seq.GetNum() << std::endl ;

    输入对象

    从标准输入cin读取字符到缓冲器,并且根据输入的第一个字符来判断输入的类别。输入token可以分为三类:数字、运算符、非法字符。其定义如下:

       1:  const int maxBuf = 16;
       2:   
       3:  //3种token类型:数字、运算符、非法字符
       4:  const int number = 1 ;
       5:  const int error = 2 ;
       6:   
       7:  class Input
       8:  {
       9:  public:
      10:      Input();
      11:      //返回运算符
      12:      int Token() const {return token ;}
      13:      //将字符转换为数字
      14:      int toNumber() const ;
      15:  private:
      16:      int token ;
      17:      char buffer[maxBuf] ;
      18:  };
    构造函数Input根据用户输入判断输入字符的类别设置token的值。如果输入是运算符,则token直接等于输入字符,并可以通过Token()访问;输入是数字,则设置token值number,可以调用toNumber将该类输入转换为数字;还允许输入负数,当输入第一个字符是‘-’时,判断输入的第二个字符是否是数字。具体实现:
       1:  Input::Input()
       2:  {
       3:      std::cin >> buffer ;
       4:   
       5:      int c = buffer[0] ;
       6:      //根据输入的第一个字符,来判断token类型
       7:      if(std::isdigit(c))
       8:          token = number ;
       9:      else if (c == '+' || c == '*' || c == '/')
      10:          token = c ;
      11:      else if ( c == '-')
      12:      {
      13:          if(std::isdigit(buffer[1]))
      14:              token = number ;
      15:          else 
      16:              token = c ;
      17:      }
      18:      else 
      19:          token = error ;
      20:  }
      21:   
      22:  int Input::toNumber() const 
      23:  {
      24:      assert(token == number) ;
      25:      return std::atoi(buffer) ;
      26:  }

    计算器

    从Input获取用户输入,实现计算功能。如果得到的输入类型是数字,则将其压入到栈中;输入是运算符,则弹出栈中元素进行运算。定义:

       1:  class Calculator
       2:  {
       3:  public:
       4:      bool Execute(Input const & input ) ;
       5:      LStack const & GetStack() {return stack ;}
       6:  private:
       7:      LStack stack ;
       8:      int calcu(int n1,int n2,int token) const ;
       9:  };

    Execute从Input获取用户输入,并决定是将输入压入到栈中,还是弹出栈中元素并调用calcu方法完成计算。

       1:  bool Calculator::Execute(Input const & input)
       2:  {
       3:          int token = input.Token();
       4:      bool status = false ;
       5:   
       6:      if(token == error)
       7:      {
       8:          std::cout << "Unknown token 
     " ;
       9:      }
      10:      else if (token == number)
      11:      {
      12:          if(stack.IsFull())
      13:          {
      14:              std::cout << "Stack is full 
    " ;
      15:          }
      16:          stack.Push(input.toNumber());
      17:          status = true ;
      18:      }
      19:      else 
      20:      {
      21:          assert(token == '+' || token == '-' || token == '/' || token == '*') ;
      22:          if(stack.IeEmpty())
      23:          {
      24:              std::cout << "Stack is empty
    " ;
      25:          } 
      26:          else 
      27:          {
      28:              int num2 = stack.Pop();
      29:              int num1 ;
      30:              if(stack.IeEmpty())
      31:                  num1 = num2 ;
      32:              else
      33:                  num1 = stack.Pop() ;
      34:   
      35:              stack.Push(calcu(num1,num2,token));
      36:              status = true ;
      37:          }
      38:      }
      39:   
      40:      return status ;
      41:  }
      42:   
      43:  int Calculator::calcu(int n1,int n2,int token) const
      44:  {
      45:      int result ;
      46:      if(token == '+')
      47:          result = n1 + n2 ;
      48:      else if(token == '-')
      49:          result = n1 - n2 ;
      50:      else if( token = '*')
      51:          result = n1 * n2 ;
      52:      else if(token == '/')
      53:      {
      54:          if(n2 == 0)
      55:          {
      56:              std::cout << "Division by zero 
    " ;
      57:              return 0 ;
      58:          }
      59:          else 
      60:          {
      61:              result = n1 / n2 ;
      62:          }
      63:      }
      64:   
      65:      return result ;
      66:  }

    测试代码就不贴出了,其执行结果:

    image

    改进

    计算器接受的输入是后缀表达式,是很不方便的,可在Input中添加一个转换,将输入的中缀表达式转换为后缀表达式后再进行计算。大声笑

  • 相关阅读:
    ffmpeg mp4 视频输出为 aac 的命令
    git操作远程分支
    Linux (openSUSE 15.3 ) server ssh 可以使用,sftp无法使用
    小小思考题
    Linux 命令介绍
    2021 年 如何使用VMware 安装 ubuntu 7.04 虚拟机, 配置 apt 源
    Linux 下 命令行 使用浏览器
    oracle.cmd
    Sqlcmd
    vue eslint 配置使用
  • 原文地址:https://www.cnblogs.com/wangguchangqing/p/3562092.html
Copyright © 2011-2022 走看看