新手C++ 练习项目--计算器
本篇博客用于记录我自己用C++实现的一个计算器,目标是完成加减乘除带括号的四则运算,并在后期用工厂设计模式加以优化。
Part 1:calculate 1+1=2
实现这样的一个式子的计算,只需要用到字符串分割即可,一开始尝试了stringstream去先读入一整个字符串"1+2",然后创建了两个临时变量int和一个char,用>>去读入,但是发现读入的char放在中间被忽略掉了
string s ="12+34"; // stringstream ss(s); // int n1,n2,c; // ss>>n1>>c>>n2;//c is 34 ,the '+' is ignored
然后我就换用了substr去进行分割,substr有两个参数,一个是开始分出字串的位置,另一个是字串的长度,第二个参数默认值是npos,也就是字符串末尾。
int i =0; while(isdigit(s[i])) { ++i;//pos } cout<<cal( atof(s.substr(0,i).c_str()) , atof(s.substr(i+1).c_str()) ,s[i])<<endl;
这样就跑出来了一个简单的1+1=2了!但这个程序改起来很麻烦,没有办法适应1+1+1=3,也没有优先级操作,等下一part我们再来做新功能。
part2:后缀表达式的使用
今天想了很久,发现自己想不出一个既能很好的处理各种符号优先级又能处理好括号的问题,这个时候各位群友的博客帮了我很大忙,我知道了一个叫后缀表达式的东西,行如 "6 5 2 3 + 8 * + 3 + *"的这种式子,运算符在操作数之后,且是可以直接用堆栈简单处理的一个不错的表达式,简单总结就是,遇到数字就压入堆栈,遇到一个符号就弹出两个操作数,计算之后又压回去,加号和减号有点不同,因为加号和减号可以写在一开头作为负号处理(switch的case里不要申请局部变量,过不去编译的,当然加个大括号表示生命周期也可以过的~)
这里有一篇不错的博客,我在这里给大家安利一下:https://blog.csdn.net/sgbfblog/article/details/8001651
附上我写的代码:
double calc(char post[]) { stack<double> sd; //stack<char> sc; char tempNum[MAX_BUFFER]; int j = 0; for(size_t i =0;post[i] != '\0';++i)//一直读到结尾 { while(isdigit(post[i])){ tempNum[j] = post[i]; ++i; ++j; tempNum[j] = '\0';//可以配合后面的直接设置i = 0 来重置tempNum if(post[i] == ' ') { sd.push(atof(tempNum)) ; j=0; } } switch(post[i]){ case '+': {//局部变量的申请,加个大括号,不然编译不过,也可以把n1 n2放到上面去声明 double n1 = sd.top(); sd.pop(); if(sd.empty()){ sd.push(n1); n1 = 0; } double n2 = sd.top(); sd.pop(); sd.push(n1+n2); break; } case '-': { double n1 = sd.top(); sd.pop(); if(sd.empty()){ sd.push(-n1); n1 = 0; } double n2 = sd.top(); sd.pop(); sd.push(n1+n2); break; } case '*': { double n1 = sd.top(); sd.pop(); double n2 = sd.top(); sd.pop(); sd.push(n1*n2); break; } case '/': { double n1 = sd.top(); sd.pop(); double n2 = sd.top(); sd.pop(); sd.push(n2/n1); break; } break; default:break; } //++i; } double total = sd.top(); sd.pop(); return total; }
这个处理后缀的表达式的函数实现了基本功能,但是如果后面的数是负数就会bug QAQ,写好一个计算器真的不容易,明天继续更新part3,中缀表达式转后缀表达式!