(C++)简单计算器

文章目录

  • 一、实验目的、内容
  • 二、实验程序设计及结构
    • 1.需求分析
      • 变量
      • 函数
    • 2.设计结构或流程图
  • 三、设计过程
  • 四、测试分析
    • 第一组
    • 第二组
    • 实验中出现的bug及解决方案
  • 五、设计的特点和结果

一、实验目的、内容

输入是一个带有括号的四则运算表达式,输出是计算得出的正确计算结果。

二、实验程序设计及结构

1.需求分析

由于待求值表达式长度不限,故采用标准库类型string存储字符串;又因为运算符个数不确定,故采用标准库类型vector存储运算符的位置。要能检查错误,故包含math.h头文件利用宏定义NAN返回错误值。要能计算小数,故采用double作运算。

变量

字符串a(string)用于存储待求值表达式;数result(double)用于存储结果。

函数

计算函数double cal(string s),主函数int main()string的成员函数,vector的成员函数以及库函数stodisnanto_string

2.设计结构或流程图

  1. 输入表达式存入a中。
  2. 调用计算函数求值,并存入b中。
    1. 输入表达式存入a中。
    2. 调用计算函数求值,并存入b中。
      1. 首先遍历字符串,若存在' ''\t'则删除之以免影响后面的计算;若存在'(',将此时的位置保存于string类下的迭代器a中,n表示嵌套'('的个数递增;若存在')'n递减,如果n减至0,递归调用计算函数以消除括号;若出现数字、运算符字符、小数点'.'以及指数'e'以外的字符或分母为0的情况,返回NAN
      2. 在递归完成后(没有'('),如果n(左括号个数减右括号个数)非零,返回NAN
      3. 处理乘除:定义向量u(vector<string::size_type>)保存'*''/'运算符的位置。从第一个运算符开始把相邻两个数用stod转换为double作运算,用to_string把运算结果转换为字符串用成员函数replace替换回原来的字符串,删除u的首元素并移动u中各元素的位置。重复上述过程直到u为空集。
      4. 处理加减:利用上面的u保存'+''-'运算符的位置,并将相邻的加减号合并。其余过程与乘除类似。
      5. 将结果转换为double并返回。
  3. 判断b的值并输出。

三、设计过程

#include <iostream>
#include <string>
#include <vector>
#include <math.h> //利用宏定义NAN
using namespace std;
double cal(string s)
{string s1;string::iterator a, b, i; // a记录'(',b记录')'string::size_type n = 0;int l;if (false)F:s.replace(a, i + 1, to_string(cal(string(a + 1, i))).c_str()); // 递归计算括号
R:i = s.begin();while (i < s.end()){if (*i == ' ' || *i == '\t'){s.erase(i);goto R;}if (*i == '('){ // 防止悬垂else问题if (!n++)a = i;}else if (*i == ')'){ // 防止悬垂else问题if (!--n)goto F;}else if (*i != '\0' && *i != '.' && *i != 'e' && *i != '*' && *i != '-' && *i != '+' && *i != '/' && (*i < '0' || *i > '9') || (*i == '/' && *(i + 1) == '0' && *(i + 2) != '.'))return NAN; // 不是数学表达式++i;}if (n)return NAN; // 左括号个数不等于右括号个数vector<string::size_type> u;// k用作bool数组// 第一位表示第一个数字的正负性// 第二位表示第二个数字的正负性// 第三位表示第一个数字是否为字符串首个数字unsigned char k = 0;// 计算乘除for (b = a = s.begin(); a < s.end(); ++a)if (*a == '*' || *a == '/')u.push_back(a - b);while (u.size()){i = a = b = s.begin() + u[0];while ((*--b >= '0' && *b <= '9') || *b == '.' || *b == 'e')if (b == s.begin()){k = 4;goto G;}// n记录第一个数字的首位的位置k += *b == '-';if (*b == '-')n = b - s.begin();elsen = ++b - s.begin();G:double t = stod(string(b, a++));doif (++a == s.end())break;while ((*a >= '0' && *a <= '9') || *a == '.' || *a == 'e');double w = stod(string(i + 1, a));k += (w < 0) * 2;if (*i == '*'){l = (s1 = to_string(t * w)).size() - (a - b);s.replace(b, a, s1.c_str());}else if (w){l = (s1 = to_string(t / w)).size() - (a - b);s.replace(b, a, s1.c_str());}elsereturn NAN; // 除数为0switch (k){case 2:s.erase(s.begin() + n - 1);break; // 删除-号前的+case 3:s.insert(s.begin() + n, '+'); // 在计算结果之前加一个+}u.erase(u.begin());for (auto &q : u)q += l;}// 计算加减
H:for (a = (b = s.begin()) + 1; a < s.end(); ++a)if (*a == '+'){if (*(a + 1) == '-' || *(a + 1) == '+'){s.erase(a);goto H;}u.push_back(a - b);}else if (*a == '-'){if (*(a + 1) == '-'){s.replace(a, a + 2, "+");goto H;}else if (*(a + 1) == '+'){s.erase(a + 1);goto H;}u.push_back(a - b);}while (u.size()){i = a = (b = s.begin()) + u[0];double t = stod(string(b, a++));doif (++a == s.end())break;while ((*a >= '0' && *a <= '9') || *a == '.' || *a == 'e');if (*i++ == '+')l = (s1 = to_string(t + stod(string(i, a)))).size() - (a - b);elsel = (s1 = to_string(t - stod(string(i, a)))).size() - (a - b);s.replace(b, a, s1.c_str());u.erase(u.begin());for (auto &q : u)q += l;}return stod(s);
}
int main()
{string a;cout << "请输入数学算术表达式:\n";cin >> a;double result = cal(a);if (isnan(result))cout << "表达式不正确!\n";elsecout << result << endl;system("pause");return 0;
}

四、测试分析

第一组

第二组

实验中出现的bug及解决方案

bug解决方案
u如果使用vector<string::iterator>在替换后可能导致u中的迭代器失效使用数字而非迭代器保存
29行需要加上*i!='\0',否则无论输入任何表达式都会报错加上条件判断
容易出现超级大数检查乘除时负负得正的情况,并在结果前加一个'+'用以区分;在每次替换完成后移动u中的元素

五、设计的特点和结果

采用递归的思想解决括号,并根据优先级和结合方向逐个处理运算符。

结果:求出表达式的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/244128.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详细分析Java中的list.foreach()和list.stream().foreach()

目录 前言1. 基本知识2. 差异之处2.1 执行顺序2.2 串行并行2.3 复杂数据处理2.4 CRUD集合2.5 迭代器 3. 总结4. 彩蛋 前言 典故来源于项目中使用了两种方式的foreach&#xff0c;后面尝试体验下有何区别&#xff01; 先看代码示例&#xff1a; 使用List的forEach&#xff1a…

手写Vue3源码

Vue3核心源码 B站视频地址&#xff1a;https://www.bilibili.com/video/BV1nW4y147Pd?p2&vd_source36bacfbaa95ea7a433650dab3f7fa0ae Monorepo介绍 Monorepo 是管理项目代码的一种方式&#xff0c;只在一个仓库中管理多个模块/包 一个仓库可以维护多个模块&#xff0c;…

打 jar 包运行 在windows 平台控制台和日志 乱码解决

--拒絕鷄巴囉嗦&#xff0c;直接解決問題 我们在Windows下运行jar包时&#xff0c;常常会出现乱码&#xff0c;主要分为dos窗口输出的日志中出现乱码和程序返回数据出现乱码。 dos窗口输出的日志中出现乱码 执行如下命令&#xff0c;将控制台输出编码改为UTF8&#xff1a; ch…

基于springboot+vue的足球青训俱乐部管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

Tkinter + removebg实现Ai抠图

我们先对removebg进行一个说明&#xff1a; "removebg" 是一个在线服务&#xff0c;它允许用户自动去除图片的背景。用户只需上传图片&#xff0c;系统会通过算法自动识别并去除背景&#xff0c;生成透明背景&#xff08;PNG格式&#xff09;或者用户指定的新背景图…

Qt6入门教程 10:菜单栏、工具栏和状态栏

目录 一.菜单栏 1.Qt Designer 1.1添加菜单和菜单项 1.2添加二级菜单 1.3给菜单和菜单项添加图标 1.4给菜单项添加功能 2.纯手写 二.工具栏 1.Qt Designer 1.1添加工具栏按钮 1.2工具栏的几个重要属性 2.纯手写 三.状态栏 1.Qt Designer 2.纯手写 用Qt Creator新…

excel学习1

直接ctrl cctrl v会报错位移选择粘贴时用123那个数字粘贴而不是ctrl V 只要结果不要公式 上面复制的为数值这里是复制的公式他们两个不一样 这个方法太麻烦了直接用格式刷&#xff0c;选择一个区域一个单元格&#xff0c;不要选择多个一刷就出来了 第一个计算后向下拖就行了&…

Overleaf(LaTeX文档在线编写平台)使用学习记录

一、LaTeX简概[1] LaTeX&#xff0c;是一种基于TEX的排版系统&#xff0c;是一种可以处理排版和渲染的标记语言。由美国计算机科学家莱斯利兰伯特在20世纪80年代初期开发&#xff0c;利用这种格式系统的处理&#xff0c;即使用户没有排版和程序设计的知识也可以充分发挥由TEX所…

SpringBoot整合ElasticSearch实现基础的CRUD操作

本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述spring-boot-starter-data-elasticsearch项目搭建ES简单的crud操作保存数据修改数据查看数据删除数据 本文小结 概述 SpringBoot支持两种技术和es交互。一种的jest&#xff0c;还有一种就是SpringData-ElasticSearch。根据…

centos7安装Redis7.2.4

文章目录 下载Redis解压Redis安装gcc依赖&#xff08;Redis是C语言编写的&#xff0c;编译需要&#xff09;编译安装src目录下二进制文件安装到/usr/local/bin修改redis.conf文件启动redis服务外部连接测试 参考&#xff1a; 在centos中安装redis-5.0.7 Memory overcommit must…

docker 部署及命令

一、容器概述 1、为什么要用到容器&#xff1f; ①容器可以屏蔽底层操作系统的差异性&#xff0c;让业务应用不管在哪里都是使用容器的环境运行&#xff0c;从而保证开发测试环境与生产环境的一致性 ②容器部署起来非常便捷和迅速&#xff0c;缩短开发测试部署的周期时间 2…

神经网络的学习(Neural Networks: Learning)

1.代价函数 案例&#xff1a;假设神经网络的训练样本有&#x1d45a;个&#xff0c;每个包含一组输入&#x1d465;和一组输出信号&#x1d466;&#xff0c;&#x1d43f;表示神经网络层数&#xff0c;&#x1d446;&#x1d43c;表示每层的 neuron 个数(&#x1d446;&#…

【Java-框架-SpringSecurity】单点登录(认证和授权)- 随笔

项目文件&#xff1b; 【1】 预览 文件 文件01 名称 pom.xml&#xff1b; 内容 &#xff08;01&#xff09;总的 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http:…

18.鸿蒙HarmonyOS App(JAVA)日期选择器-时间选择器

18.鸿蒙HarmonyOS App(JAVA)日期选择器-时间选择器 点击button按钮触发事件显示月份与获取的时间 Button button3 (Button) findComponentById(ResourceTable.Id_button3);button3.setClickedListener(new Component.ClickedListener() {Overridepublic void onClick(Compon…

【趣味CSS3.0】粘性定位属性Position:sticky是不是真的没用了?

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起学习和进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&a…

Webpack5 基本使用 - 2

常用 loader loader 是辅助打包工具。webpack 默认只能打包 js 文件&#xff0c;打包其它模块就需要配置 loader 来告诉 webpack 该怎么去打包其它文件。loader 可以将文件从不同的语言转换为 JavaScript。一类文件如果需要多个 loader 处理&#xff0c;loader 的执行顺序是从…

SQL注入 ---> Day1 !

终于&#xff0c;我的课程开始讲SQL注入了&#xff0c;对就是那个常年在OWASP上有名的SQL注入 今天是真的冷啊&#xff0c;幸苦的小编还在写csdn 1.SQL注入原理 SQl注入其实就是将恶意的代码向服务器提交&#xff0c;但是后端又不过滤而引发的漏洞&#xff0…

2、Line Charts折线图

可视化时间趋势 现在你已经熟悉了编码环境,是时候学习如何制作自己的图表了! 在本教程中,您将学习足够的Python来创建专业外观的折线图。然后,在接下来的练习中,您将使用您的最新技能处理真实世界的数据集。 本课程数据集夸克网盘下载链接:https://pan.quark.cn/s/a235ac…

让二叉树无处可逃

志不立&#xff0c;天下无可成之事。 ——王阳明 二叉树 1、树&#xff1f;什么是树1、1、基本概念1、2、树的相关概念1、3、树的表示方式1、4、树的实际运用 2、二叉树&#xff1f;只有两个分支吗&#xff1f;2、1、基本概念2、2、二叉树的相关定义2、3、二叉树的相关性质2、4…

flutter获取地理定位:geolocator依赖详细用法

本文使用geolocator插件实现app物理定位功能。 该插件的主要功能有&#xff1a; 获取最后已知位置&#xff1b;获取设备当前位置&#xff1b;获取连续的位置更新&#xff1b;检查设备是否启用了定位服务&#xff1b;计算两个地理坐标之间的距离&#xff08;米&#xff09;&am…