本人写了一个简单的计算器实现代码,能实现+-*/及()功能.特此备案.
一、开发环境:
Linux操作系统(Fedora虚拟机), vim、g++等开发环境。
二、核心算法
1、 int Test(string str): 对输入的const string类型字符串(计算式)进行检测,发现其是否为一正确的计算表达式,如果是则return 1,如果否则return 0。如“12+23”为正确则返回1,“12*&45”为错误计算式,则返回0。
2、 string stringtoarr(const stringstr):对输入的无括号的conststring类型字符串str进行单元转换,将最终返回其值,如果某个单元“12+23*2”,则将之返回为“58”。
3、 string trims(const string&sub):将输入的带括号的字符串进行去括号操作,最后返回无括号的表达式(对带括号的子字符串部分进行stringtoarr处理,去除括号)。这是一个递归函数,如果子字符串中含有多个括号,则反复地自递归调用。
三、编译与链接
在虚拟机环境下,使用vim环境指令创建Calculation.cpp文件,并用g++进行编译与链接g++ Calculation.cpp –oCal.out。并使程序能正常进行实现计算器功能。
四、自测试报告。
1、对生成的Cal.out文件进行运行,并进行测试用例自测试过程(正异常用例共7组):
正常用例测试:
第一组(加减):12.2+23.0 24+34.6+34+7854.3 56-23.3+23.5-0.12
第二组(乘除):17/56 23*45.75 12.04/34 23.77/34.901*23.0 23.04*0/34.2
第三组(+-*/混合):23.4*23.5/34 23+234*34.3/45.9-23/23.04
第四组(+-*/混合,带一个或多个括号):
(12-45.4)/23.78 (12*23.5-23/(25.7-34.6))*12 2*(12-(45.5*(12.3*(11.92-6))-12.4)*2.3)
错误用例测试:
第一组(字符错误):12<23.2-34.6 89.6/56,2+2 23%7 21^2 2a.0-12 12”3-12
第二组(被除数为零): 12/0.0+12
第三组(式中括号有误): 12-(12.7*(35-45.8)+2 12-(12.7*)35-45.8)+2 12*)34-98(-23
2、部分测试报告截图如下:
*说明:此计算器代码相对较简单,是以一个.cpp文件将三个子函数全部写下。如果在建立的工程需要将子函数写成不成同的.cpp文件,则需要用到Makefile,规定每个程序源文件的编译顺序,否则改动程序时会经历循环反复的编辑à编译à测试过程,比较费时。
五、审评意见:
使用递归算法实现计算器功能,代码相对简洁,但编码不太规范,希望在以后的编码工作中加强规范编码的训练。
附录代码:
//Calculation.cpp : 定义控制台应用程序的入口点。
//
//#include"stdafx.h"
#include<stdio.h>
#include<iostream>
#include<string>
#include<stdlib.h>
#include<fstream>
usingnamespace std;
intTest(string as)
{
string::size_type len=as.size();
string::size_type i=0;
int k=0;
while(i<len)
{
if(!((as[i]>='0' &&as[i]<='9') || as[i]=='+' || as[i]=='-' || as[i]=='*' || as[i]=='/'||as[i]=='.' || as[i]=='(' || as[i]==')'))
{
cout<<"输入的表达式错误,请重新输入!"<<endl;
return 0;
}
if(as[i]=='/'&&as[i+1]=='0')
{
cout<<"分母不能为零!"<<endl;
return 0;
}
if(as[i]=='(')
k++;
else if(as[i]==')')
{
k--;
if(k<0)
return 0;
}
i++;
}
if(k!=0)
{
cout<<"括号输入错误!"<<endl;
return 0;
}
return 1;
}
stringstringtoarr(const string str) //将一个字符串转化成两个数组,一个为数字数组保存数字,另一个为字符数组,保存符号
{ //此函数将用于无括号的计算。
int i=0,z=0,s,temp;
float rate=10.0,itemp=0.0;
float valueStr=0.0;
float a[40];
char b[20];
for(i=0;i<40;i++)
a[i]=0.0; //对数组a[20]初始化
for(i=0;i<20;i++)
b[i]=' '; //对数组b[10]初始化
i=0; //把0赋给i
for(i=0;i<str[i];i++)
{
if(str[i]>='0'&& str[i]<='9') //如果字符串str.GetAt(i)的内容是整数
{
if(rate==10.0) //整数部分
itemp=itemp*rate+(str[i]-'0'); //获得整数
else //小数部分
{
itemp=itemp+rate*(str[i]-'0'); //获得小数
rate=rate/10; //每次让rate小10倍
}
}
elseif(str[i]=='.') //如果str.GetAt(i)是小数点
rate=0.1; //让rate=0.1,开始计算小数部分
elseif(str[i]=='+') //如果str.GetAt(i)是加号
{
a[z]=itemp;itemp=0; //把itemp的值放入双精度数组a中,并把itemp的值改为0
z++; //让z自加一次
b[z]='+'; //把加号放入字符数组b中
z++; //让z自加一次
rate=10.0; //把10赋给rate,确保读取下个数字时,先计算整数部分
}
else if(str[i]=='-') //如果str.GetAt(i)是减号
{
a[z]=itemp;itemp=0; //把itemp的值放入双精度数组a中,并把itemp的值改为0
z++; //让z自加一次
b[z]='-'; //把减号放入字符数组b中
z++; //让z自加一次
rate=10.0; //把10赋给rate,确保读取下个数字时,先计算整数部分
}
else if(str[i]=='*') //如果str.GetAt(i)是乘号
{
a[z]=itemp;itemp=0; //把itemp的值放入双精度数组a中,并把itemp的值改为0
z++; //让z自加一次
b[z]='*'; //把减号放入字符数组b中
z++; //让z自加一次
rate=10.0; //把10赋给rate,确保读取下个数字时,先计算整数部分
}
else if(str[i]=='/') //如果str.GetAt(i)是除号
{
a[z]=itemp;itemp=0; //把itemp的值放入双精度数组a中,并把itemp的值改为0
z++; //让z自加一次
b[z]='/'; //把除号放入字符数组b中
z++; //让z自加一次
rate=10.0; //把10赋给rate,确保读取下个数字时,先计算整数部分
}
}
a[z]=itemp; //把最后一个整数itemp的值放入双精度数组a中
s=z; //把z的值赋给变量s,用来控制计算结果的循环中的条件,s即为数与值的大小。
for(i=0;i<=s;i++)
{
if(b[i]=='/') //当循环遇到除号时
{
a[i+1]=1/a[i+1]; //把a[i+1]的值改为1/a[i+1]
b[i]='*'; //把b[i]的值改为乘号
}
}
for(i=0;i<=s;i++)
{
while(b[i]=='*') //当循环遇到乘号时
{
a[i-1]=a[i-1]*a[i+1];
for(temp=i+1;temp+2<40;temp++)
a[temp]=a[temp+2];
for(temp=i;temp+2<20;temp++)
b[temp]=b[temp+2];
}
}
valueStr=a[0];
for(i=0;i<s;i++)
{
if(b[i]=='+')
valueStr+=a[i+1];
else if(b[i]=='-')
valueStr-=a[i+1];
}
char svalue[16];
sprintf(svalue,"%f" , valueStr);
string ssavalue(svalue);
return ssavalue;
}
stringtrims(const string &sub)
{
string s1,s2,s3,sp,ss;
int i;
int counter=0;
int left,right;
if(string::size_typepos1=sub.find(")")==string::npos)
return sub;
for(i=0;sub[i];i++)
if(sub[i]=='(')
{
left=i;
counter++;
break;
}
for(i=left+1;sub[i];i++)
{
if(sub[i]=='(')
counter++;
else if(sub[i]==')')
counter--;
if(counter==0)
{
right=i;
break;
}
}
s1=sub.substr(0,left);
sp=sub.substr(left+1,right-left-1);
s2=stringtoarr(trims(sub.substr(left+1,right-left-1)));
s3=trims(sub.substr(right+1));
ss=s1+s2+s3;
return ss;
}
voidcalcation(string &str1)
{
int stTe;
if((stTe=Test(str1))<=0)
{
cout<<"输入字符串有误,请重新输入!!!"<<endl;
return;
}
string sk=trims(str1);
string ssk=stringtoarr(sk);
cout<<ssk<<endl;
cout<<"--------------------"<<endl;
}
intmain()
{
string input_str;
int p=1;
int tsTest;
//string tss;
while(1)
{
cout<<"请输入表达式(退出请输入小写exit):"<<endl;
cin>>input_str;
cout<<endl;
if(input_str.compare("exit")==0)
break;
if((tsTest=Test(input_str))==1)
{
calcation(input_str);
//tss=trims(input_str);
//cout<<stringtoarr(tss)<<endl;
}
}
cout<<"Close this calculation!"<<endl;
return 0;
}