C++ 单位整型计算器,仅支持带括号的四则运算。初学c++第一个个人作品
2016-04-09 11:42
549 查看
//本程序实际意义并不大,初学C++小试牛刀,但是本程序并没有体现出C++语言程序的特点,即主函数简短。但实际上,主函数大部分内容可以转换成一个普通函数,所以这里不再处理。
//这篇博客算是给自己第一个C++个人作品的纪念。
//但愿这篇博客能给其他初学者一个参考,大家共同进步,也希望各位大大能予以指点,帮助。
接下来讲讲思路。
1,中缀表达式转后缀表达式,借助栈进行运算。我一开始是拒绝好多东西的,比如动态申请内存,使用后缀表达式...但后来渐渐地接受了,因为这些算法确实方便了许多。也希望广大学习者别太排斥新东西(好吧可能就我不太容易接受,但总要接受的)。
2,用共用体存储 char类型数据和(double)int型操作数。写之前我也是在网上找了好多文章,有的有400多行代码,中间含有三角函数的运算啥啥的,比较高端,也没静下心来看,最后自己想到用共用体来解决运算符和操作数的存储问题。期间有同学跟我讲到了vector这个东西,但是不太会用,就放弃了。
3,有两个地方想用goto语句,个人觉得goto语句真心好,但是这样破坏了程序编写的结构,后面一处解决了,前面一处是做输入检查,遇到异常了直接goto回重新输入。
4,try catch结构语句。这里讲讲,这个语句完全可以不需要,因为检查时一旦遇到问题可以直接goto回重新输入。为什么这里用了些 try catch语句呢,因为本人最近才学习到这个东西,只看不练的学习是没有效果的,所以我就试了一下。学习前辈不能只看不编的思想。
5,最后扯两句。我专业与计算机有关,但并不是学软件工程的,打代码有相当一部分原因是个人兴趣,嗯...就像一些人喜欢玩游戏一样。学习还是在于兴趣嘛
第一次写博客,说了这么多,下面上源代码,里面基本都有注释,注释有点多,大家一起学习,哈哈哈...
在vc++6.0下可以运行,VS还不太会用,还没做测试。c4droid也可以运行。
由于打着原创的牌子,所以这里不引入中缀表达式转后缀表达式的方法,大家自行百度吧,不是很难,写之前我也是硬要用中缀表达式来搞的,后来还是学会了。
大家共同进步吧。
--Ch. 原创
//这篇博客算是给自己第一个C++个人作品的纪念。
//但愿这篇博客能给其他初学者一个参考,大家共同进步,也希望各位大大能予以指点,帮助。
接下来讲讲思路。
1,中缀表达式转后缀表达式,借助栈进行运算。我一开始是拒绝好多东西的,比如动态申请内存,使用后缀表达式...但后来渐渐地接受了,因为这些算法确实方便了许多。也希望广大学习者别太排斥新东西(好吧可能就我不太容易接受,但总要接受的)。
2,用共用体存储 char类型数据和(double)int型操作数。写之前我也是在网上找了好多文章,有的有400多行代码,中间含有三角函数的运算啥啥的,比较高端,也没静下心来看,最后自己想到用共用体来解决运算符和操作数的存储问题。期间有同学跟我讲到了vector这个东西,但是不太会用,就放弃了。
3,有两个地方想用goto语句,个人觉得goto语句真心好,但是这样破坏了程序编写的结构,后面一处解决了,前面一处是做输入检查,遇到异常了直接goto回重新输入。
4,try catch结构语句。这里讲讲,这个语句完全可以不需要,因为检查时一旦遇到问题可以直接goto回重新输入。为什么这里用了些 try catch语句呢,因为本人最近才学习到这个东西,只看不练的学习是没有效果的,所以我就试了一下。学习前辈不能只看不编的思想。
5,最后扯两句。我专业与计算机有关,但并不是学软件工程的,打代码有相当一部分原因是个人兴趣,嗯...就像一些人喜欢玩游戏一样。学习还是在于兴趣嘛
第一次写博客,说了这么多,下面上源代码,里面基本都有注释,注释有点多,大家一起学习,哈哈哈...
#include<iostream> #include<stack> #include<string> using namespace std; int judge(char a); //judge函数声明,用于判断数据类型 int judge(char a) //judge函数定义 { switch (a) { case '*': case 'x': case 'X': case '/': return 3; case '-': case '+': return 2; case '(': return 1; case ')': return -2; default :return -1; } } //可用于优先级 int main() { string str; cout<<"请不要使用全角符号和中文符号"<<endl; cout<<"请勿输入小数,多位数,以及不要省略乘号"<<endl; checkagain: // checkagain为goto语句标号,在每次捕获异常后都要进行重新输入数据 cout<<"请输入表达式:"; cin>>str; //保存外部输入的数据,即表达式 int len =str.size(); //外部数据长度 /*表达式初步检查*/ try{ cout<<"表达式初步检查..."<<endl; int count0=0; double checkdouble; int checkbracket; char support; long checktwo; float checkdiv; for (int e=0;e<len;e++) { if (str[e]=='(') { count0++; if (e!=0) if (str[e-1]>='0'&&str[e-1]<='9') throw support; //不支持省略乘号,比如2(3+5) char } if (str[e]==')') { count0--; if (e+1<len) if (str[e+1]>='0'&&str[e+1]<='9') throw support; //不支持省略乘号,比如(3+5)2 char } if (str[e]=='.') throw checkdouble; //不支持小数,如1.2 double if (str[e]>='0'&&str[e]<='9') { if (str[e+1]>='0'&&str[e+1]<='9') throw checktwo; //不支持两位数及以上,如16 long } if (str[e]=='/') if (str[e+1]=='0') throw checkdiv; //检查除数为0 float } if (count0!=0) throw checkbracket; //检查括号是否配对 int } catch (int) { cout<<"括号不配对,请重新输入"<<endl; goto checkagain; } catch (char) { cout<<"不支持省略乘号,请重新输入"<<endl; goto checkagain; } catch (double) { cout<<"不支持小数,请重新输入"<<endl; goto checkagain; } catch (long) { cout<<"不支持两位数及以上,请重新输入"<<endl; goto checkagain; } catch (float) { cout<<"被除数不允许为0,请重新输入"<<endl; goto checkagain; } catch (...) { cout<<"出现未知异常"<<endl; goto checkagain; } cout<<"表达式检查完毕."<<endl; /*表达式检查完毕*/ //考虑到除号后面可能出现的 由int型数据作除法 除数为 表达式中int型计算得到的整型数据0(比如2/(2-5/2)会出现运算错误),故本程序操作数的存储和计算数据均用double型数据 //本程序无法对类似 2/(2-2) 的运算式做检查 union uu{double d;char c;}; //定义共用体,用于不定型数据的存储:,操作数或者运算符 uu *u=new uu[len]; //由外部的相关数据来确定申请的内存大小 //申请共用体的动态内存,u为指向其首地址的指针 int j=0; //结构体组下标 stack<char> s; //临时存放运算符 stack<double> dd; //用于最后数学计算 for (int i=0;i<len;i++) //扫描合法字符串表达式 { if (judge(str[i])==-2) //遇到右括号 { for (;;) //"死"循环,但是合法表达式中一定有左括号 { //处理括号之间的运算符 if (s.top()=='(') break; u[j].c=s.top(); s.pop(); j++; //j为共用体单独计数,每存储一个数据,下标(指针)移动一位 } s.pop(); //删除左括号 } if (judge(str[i])==-1) //遇到数字 { u[j].d=(double)(str[i]-48); //将字符型数字转化为10进制double数据 j++; } if (judge(str[i])>0) //遇到运算符 { if (str[i]=='(') //优先判断是否为左括号 {s.push('(');continue;} //左括号入栈,立即进入下一轮循环 if (s.empty()) //栈空 则入操作符 s.push(str[i]); else //遇到运算符但栈不空 { while (judge(s.top())-judge(str[i])>=0)//优先级判断并做相应处理。此处为出栈处理。 { u[j].c=s.top(); s.pop(); j++; if (s.empty()) //如果栈空,即运算符全部出栈,则退出while循环 break; } 4000 s.push(str[i]); //此处为入栈处理。 } } } while (!s.empty()) //将栈中运算符元素全部出栈,直至空。 { u[j].c=s.top(); s.pop(); j++; } double r; //中缀表达式 转 后缀表达式 已全部转换完成,进入后缀表达式运算阶段 for (int z=0;z<j;z++) //用j(最终所使用的共用体个数,即后缀表达式数据的个数)做控制 { if (u[z].c=='*'||u[z].c=='x'||u[z].c=='X') { r=dd.top(); dd.pop(); dd.top()=dd.top()*r;//先取出的数据放在后缀表达式的右边 //数栈顶是每步运算后的结果 } else if (u[z].c=='/') { r=dd.top(); dd.pop(); dd.top()=dd.top()/r; } else if (u[z].c=='-') { r=dd.top(); dd.pop(); dd.top()=dd.top()-r; } else if (u[z].c=='+') { r=dd.top(); dd.pop(); dd.top()=dd.top()+r; } else {r=u[z].d;dd.push(r);}//将后缀表达式中的数据取出来,入数栈。由于共用体不能作为函数参数,所以用变量r来作为中间值,进行传参 } cout<<"答案是"<<dd.top()<<endl; return 0; }
在vc++6.0下可以运行,VS还不太会用,还没做测试。c4droid也可以运行。
由于打着原创的牌子,所以这里不引入中缀表达式转后缀表达式的方法,大家自行百度吧,不是很难,写之前我也是硬要用中缀表达式来搞的,后来还是学会了。
大家共同进步吧。
--Ch. 原创
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Linux C函数参考手册(PDF版)
- C# partial关键字说明
- Lua中调用C++函数示例
- Lua教程(十七):C API简介
- 简单谈谈lua和c的交互
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C#中的委托数据类型简介
- C++联合体转换成C#结构的实现方法
- C#编写的艺术字类实例代码
- C#实现打造气泡屏幕保护效果
- 举例讲解C#编程中委托的实例化使用
- 使用C#代码获取存储过程返回值
- C++高级程序员成长之路
- C++编写简单的打靶游戏