文本输入形式计算器------bug不断修复中。。

来源是这样,想写一个计算器的程序,以文本文件的(input.txt)的形式读入,每行一个多项式,支持括号(英文格式---半角)的运算,每行的运算结果输出到result.txt中,具有一定的容错能力,如能检测/0,浮点%,只有运算符或括号没有数据等,其实我的目的就是尽量使自己的程序在错误的输入下不崩溃。没事的时候还在测试调试。。。现在主要是两个,一个是3.4.5.6这种错误输入没有给出bad input提示,另外功能上不支持负数运算。。。。应该还有其他的。。(一个程序折腾这样,尽显菜鸟本质啊哈哈)

寻思着计算器程序很简单,但是一下手,各种错误,尤其测试各种情况,可能是自己么有掌握专业的测试方法,一些极端输入总是造成程序崩溃,另外写程序的思路应该也有问题,写完后看感觉好乱,写的时候也没及时考虑各种情况。

如果有高手给我指点下如何高效规范的写出这样的应用程序就好了。

思路是这样的,先读多项式,用两个栈,一个用来存储数据,一个用来存储运算符。主要是围绕运算符的栈,比较运算符的优先级决定是入栈还是先运算再入栈。

#include <iostream>

#include<cstdlib>

#include<cmath>

//这里我就把它做成一个支持文件格式的批处理计算器(这名字咋样哈哈,但是不支持负数计算)

//总的来说,犯的最大的错误就是用stack的top,pop等操作,没想到考虑其为空,所以导致各种崩溃

#include<stack>

#include<fstream>

using namespace std;

int IsOperator(char c); //判断是不是运算符

int OperatorPro(char Oc); //判断运算符的优先级

float ChartoFloat(stack<char>& CC); //char转换成float,针对多位数,因为每次读入一个字符

float Compute(float a,float b, char c); //用取出的数字和运算符做运算

void PushWaitData(stack<char>& COperatorStack, stack<float>& CDataStack); //取出优先级低的运算符计算,后结果入栈

int main()

{

ifstream fin;

ofstream fout;

char tempc;

stack<char> OperatorStack;

stack<char> Datatemp;

stack<float> DataStack;

fin.open("input.txt");

fout.open("result.txt",ios_base::out | ios_base::app);

if(!fin.is_open())

{

cout <<"there is no such file !" << endl;

exit(EXIT_FAILURE);

}

while(1)

{

tempc = fin.get();

if(fin.eof()) break;

if (‘\n‘ == tempc)

fout << ":    ";    //只是为了让格式好看点

else

fout << tempc;

if(IsOperator(tempc) == 0)  //判断如果是数字的话,包括小数点

{

Datatemp.push(tempc);

}

if (IsOperator(tempc) == 1)  //判断如果是运算符

{

if (!Datatemp.empty())

{                            //这里问题是如何处理多位数的问题

DataStack.push(ChartoFloat(Datatemp));  //这里应该用引用传递,因为copy这里是不是还得清空元素(改成引用了,其函数内有pop)

}

//按理说这里,为空时返回肯定少于,为什么还得判断(因为后面有栈的.top动作,为空就崩溃)

if ( OperatorStack.empty()|| OperatorPro(tempc) >= OperatorPro(OperatorStack.top()) )  //如果运算符的级别高于栈定的级别则压入

{                                               //上面变成>=时,避免了全是+++(同级别连续运算符)类型造成的崩溃,原因是没=就进入else里Pushdata了,连续几个+++就调用了,(未考虑边界(=)问题)

if (‘)‘ == tempc)        //是右括号时特殊

{

cout << "it is ) " << endl;         //这是检测是否查到( 一开始总是不对,居然是因为输入是中文(,检测的是英文的(, 这里要求用英文,否则除了这里得判断,判断优先级也得判断

while(OperatorStack.size()!= 0 && OperatorStack.top() != ‘(‘)

{

try{

PushWaitData(OperatorStack,DataStack);

}

catch(const char* es)

{

fout << es << endl;

continue;

}

}

if (OperatorStack.size()!= 0) OperatorStack.pop();  //推出‘(’

}

else

{

OperatorStack.push(tempc);

}

}

else                                                         //如果优先级小于的话则要出栈运算,直到碰到大于

{

if (OperatorStack.top() == ‘(‘)

{

cout << "it is ( " << endl;

OperatorStack.push(tempc);    //‘(‘优先级是7 但是不能把前面的都计算了是不

}

else

{

while(OperatorStack.size() != 0 && OperatorPro(tempc) <= OperatorPro(OperatorStack.top()) )//这里多个运算符时一直崩溃,把判断0放到另一个判断条件前后就好了,因为判断的执行顺序,

//如果先判断优先级,top无值就会崩溃,把判0提前后不满足就不执行后面的判断了,细节

{

try{

PushWaitData(OperatorStack,DataStack);

}

catch(const char* es)

{

fout << es << endl;

continue;

}

cout << "OperateStack size after pushwait :" << OperatorStack.size() << endl;

}

OperatorStack.push(tempc);                      //把级别比其高的出栈后,把现有运算符压入(上面就纠结了好久就忘了这个,所以编程习惯,要先写上,再具体分析上面的函数,纠结过后就不会因为细节忘了逻辑了)

}

}

}

if(‘\n‘ == tempc)       //原本这里为了防止只有换行符崩溃的情形加了检查operat是否为空(错了,其实应该检查datastack,关于opera的操作前面都由有检查),造成了漏下只有一个数字没有运算符的情形

{

cout << "in huan hang " << endl;

cout << Datatemp.empty() << endl;

if (!Datatemp.empty())

{

DataStack.push(ChartoFloat(Datatemp));  // 处理最后一个数字,前面是碰到运算符处理,不适用于最后一个数字(没考虑边界问题)

}

cout << " DataStack.size():" <<DataStack.size() << endl;

cout << " Operator.size():" <<OperatorStack.size() << endl;

while ((DataStack.size() > 1)&&(!OperatorStack.empty()))  //加了大于1的判读是为了防止操作符数目大于数据个数时的错误输入导致崩溃(data为空的pop,top),其错误信息在下面的排空operator中输出

{

try{

PushWaitData(OperatorStack,DataStack);

}

catch(const char* s)

{

fout << s ;

continue;

}

}

while(!DataStack.empty())                        //有空换行符崩溃是这里datastack为空而调了top,改到这里判断,考虑到只有一个数无运算符的情形if改成while是判断一行多个空格的数无操作符的情形,免得留在栈中影响下面的结果),否则其实运算过后这里肯定有一个数的

{

fout << "The line result is : " << DataStack.top();

DataStack.pop();          //全部推空,确保不影响下一行的计算

}

if (!OperatorStack.empty())

{

fout << "Bad input :";

while(!OperatorStack.empty())   //如果有运算符多的,必须排空,否则影响下行的计算

{

fout << OperatorStack.top() << " ";

OperatorStack.pop();

}

}

fout << endl;  //最后一个换行就好了

}

}

fin.close();

fout.close();

return 0;

}

void PushWaitData(stack<char>& COperatorStack, stack<float>& CDataStack)

{

cout << "in Pushwait Data " << endl;//为了检查运行到哪里崩溃的笨法

char oc = COperatorStack.top();

COperatorStack.pop();             //两个连续pop出错了。因为先前忘了推进最后一个数,而出了这个程序后还有个pop

float oa,ob;

if (CDataStack.empty())

{

return ;

}

else

{

oa = CDataStack.top();

CDataStack.pop();

}

if (CDataStack.empty())

{

return;

}

else{

ob = CDataStack.top();

CDataStack.pop();

}

cout << "ob: oa: oc :" << ob << " " << oa << " " << oc << endl;

cout << "compute result: " << Compute(ob,oa,oc) << endl;

CDataStack.push(Compute(ob,oa,oc));   //注意这里oa,ob的顺序,oa是后来的数

cout << "out Pushwait" << endl;

}

float Compute(float a, float b, char c)

{

float result = 0.0;

switch (c) {

case ‘+‘:

result = a + b;

break;

case ‘-‘:

result = a - b;

break;

case ‘*‘:

result = a * b;

break;

case ‘/‘:

if (0 == b) {throw "bad input cause a/b b = 0!";}

result = a / b;                        //除数不能为0(这里可以用抛出异常来解决)

break;

case ‘%‘:

if((a - (int)a) != 0 || ( b-(int)b ) != 0) throw "bad input cause float % !";

else

{

result = (float)((int)a%(int)b);         //浮点数不能取余

break;

}

case ‘^‘:

result = pow(a,b);

break;

default:

break;

}

return result;

}

float ChartoFloat(stack<char>& CC)

{

int n = CC.size();

cout << "Dataemp size is :" << n << endl;

int flag = 0;     // 标记小数点的位置

float Tdata = 0.0;

char* tempcdata = new char[n];

for(int i = 0 ; i < n; i++)

{

*(tempcdata + i ) = CC.top();

CC.pop();

if (‘.‘ == *(tempcdata + i))

flag = i;

}

for (int i = 0; i < flag ; ++i)  //找出小数点的位置后,小数点前乘和小数点后乘

Tdata += ((int)(tempcdata[i] - ‘0‘)) * pow(0.1,double(flag - i));  //这里转换用这样么??

for (int i = flag ; i < n; ++i)

Tdata += ((int)(tempcdata[i] -‘0‘)) * pow(10.0,double(i - flag));

cout << "Tdata is : " << Tdata << endl;

return Tdata;

}

int IsOperator(char c)

{

if ( ‘(‘ == c ||‘)‘ == c ||‘+‘ == c ||‘-‘ == c ||‘*‘ == c ||‘/‘ == c ||‘^‘ == c ||‘%‘ == c )

return 1;

else

{

//是数字或者小数点

if(‘.‘ == c ||‘0‘ == c ||‘1‘ == c ||‘2‘ == c ||‘3‘ == c ||‘4‘ == c ||‘5‘ == c ||‘6‘ == c ||‘7‘ == c ||‘8‘ == c ||‘9‘ == c )

return 0;

else return -1;  //其他的返回-1

}

}

int OperatorPro(char Oc)

{

//其实这里我在想用switch还是用if效率高

if (‘(‘ == Oc) return 6;

if (‘)‘ == Oc) return 5;

if (‘^‘ == Oc) return 3;

if (‘%‘ == Oc) return 2;

if (‘*‘ == Oc) return 2;

if (‘/‘ == Oc) return 2;

if (‘+‘ == Oc) return 1;

if (‘-‘ == Oc) return 1;

return 0;

}

时间: 2024-10-07 17:36:59

文本输入形式计算器------bug不断修复中。。的相关文章

浏览器bug和修复2

拥有布局 Window IE上的bug要比其他浏览器多,原因之一是,IE的显示引擎使用一个称为布局(layout)的内部概念.因为布局是专门针对显示引擎内部工作方式的概念,所以一般情况下不需要了解它,但是,布局问题是许多IE/Win显示bug的根源,所以理解这个概念以及它如何影响CSS是有帮助的. 什么是布局 Windows上的IE使用布局概念来控制元素的尺寸和定位.那些称为拥有布局(have layout)的元素负责本身及其子元素的尺寸和定位.如果一个元素没有拥有布局,那么它的尺寸和位置由最近

OJ刷题常用的4中基本输入形式

初到OJ网站上刷题,输入形式就是我们要考虑的问题.通过自己的一些摸索,OJ题目的输入形式大体上无外乎4种.下面就详细介绍: 1 输入数据文件中,第一行数据标明了测试数据的数目: 2 输入数据文件中,有标明输入结束的数据 3 输入数据文件中,测试数据一直到文件尾 4 没有输入数据 第1中情形的处理方法: //int i,kase scanf("%d",&kase); for(i=1;i<=kase;i++) { //处理第i中情况 } ...................

Cocos2d-x 3.4 之 文本输入之 EditBox

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 上一篇,说了 文本输入的 CCTextFieldTTF, 这次继续来弄文本输入,EditBox 做完CCTextFieldTTF以后,马上就搞这个EditBox了, 但是,改动有些多,而且好多BUG啊,网上资料也不多,整的我焦头烂额... 先发一些基础的,具体其

Android Design新控件之TextInputLayout(文本输入布局)

谷歌在推出Android5.0的同时推出了全新的设计Material Design,谷歌为了给我们提供更加规范的MD设计风格的控件,在2015年IO大会上推出了Design支持包,Design常用的新控件包括: TextInputLayout(文本输入布局) TabLaout(选项卡布局) Snackbar FloatingActionButton(浮动按钮) NavigationView(导航视图) AppBarLayout(程序栏布局) CoordinatorLayout(协作布局) Col

EasyTable2.0 功能更加强大,bug全面修复的html table插件!

最近整理和修复了1.0的全部bug,并且给2.0添加了不少新功能.由于语法上有些修正,所以我重新写了一个非常详细的demo.html在文档里面,这里直接贴出(由于添加了新的功能,et的2.0的压缩版本已经达到了20k的体积了,虽然略显大一些,但是我相信从功能上来讲觉得是划得来的.): <html> <head> <title></title> <style type="text/css"> * { margin: 0; pad

iOS9使用提示框进行文本输入的正确实现方式

我在之前写过一篇博客<iOS9使用提示框的正确实现方式>,主要讲了如何使用UIAlertController替换UIAlertView进行提示框的实现.今天我们将会来实现一下在提示框中如何进行文本输入.该功能可以让用户进行密码确认等功能. 实现代码如下: #import "SecondViewController.h" #import "AppDelegate.h" @interface SecondViewController () @end @imp

浏览器bug和修复

与许多编程语言相比,CSS是一种相当容易学习的语言,它的语法简单明了,而且由于它的表现本质,开发人员并不需要处理复杂的逻辑.但是在不同的浏览器上测试代码才是真正困难的开始,你的设计在一种浏览器上表现的良好,但是在另外一个浏览器上就会变得“支离破碎”. “CSS难以掌握”的误解并非来自于语言本身,而是由于为了让站点在所有主流浏览器上工作正常需要采取很多的措施.关于bug的信息很难找到,缺乏文档记录,因此bug常常被误解.许多人把招数看做魔法子弹,认为它们就像神秘的咒语一样,当应用在代码中时,就会神

文本输入

1.隐藏文本框的键盘,Return类型设为UIReturnKeyDone,代理方法textD\FieldShouldReturn,视图控制器可以强令键盘留在键盘上,重写disablesAutomaticKeyBoardDismissal 2.UITextInputTraints协议中的属性:autocapitalizationType文本的自动大写,autocorrectionType自动修正,spellCheckingType是否进行拼写检查,keyboardAppearance键盘风格,ke

转载:ios程序编译链接参数 all_load 的 ld duplicate symbol _main 的 bug及修复

转载自:http://www.cnblogs.com/dabaopku/archive/2012/12/12/2813940.html ios程序编译链接参数 all_load 的 ld duplicate symbol _main 的 bug及修复 问题 -all_load 是在Objective-C 编译时常用到的一个参数,比如这篇文章所介绍的,生成静态库的一些问题-all_load.但是我们在加入这个参数后,有时会出现"ld: duplicate symbol _main"的错误