(一) 需求和规格说明
输入是一个带有括号的四则运算表达式,输出是计算得出的正确计算结果。例如:输入:123+213-67*34+345/23*45*(34+34-345+245+567)回车,然后程序计算得出结果为:359183。
(二)设计:
1.首先我想到不能打空格的话还能分开存储于是我先用到了字符串。
2.接着我将问题分开解决,因为输入的是一个char型,我首先做的是先将其转换为int型的数据,然后又开一个数组(num)进行储存。在用在字符串中的排列顺序,将每个数值都乘上一个10的阶乘进行运算,然后储存进入数组(NUM).
3.然后就是计算加减的问题了,一开始这个是花了一点时间的,因为顺序的问题总是会录入错位的数据,后来在草稿纸上写了一下就弄好了,这也让我觉得在草稿纸上写一下,把自己当做编译器是一件有趣的事。
4.接着就是乘除,我一开始觉得和加法没什么不同啦,就是指将乘除放在前面而已,但是后来才发现,机器不是人,他们能想到是只有我们给他们的,比如3+4*5和4*5+3是不一样的,我们需要改变的对所有的情况判断,要能让计算机有这个判断的能力运算所有的运算列。
5.这个做了之后我就开始考虑括号的问题了,一开始我做了前面的时候我以为也很简单但是我觉得我真的太嫩,我就想到了首先规定了运算等级,然后这就和生活一样就可以了,括号最大,接着乘除,然后是加减。于是我将括号内的运算单独形成了一个小世界,设置了多个单独的数组进行储存。最后只要将整个括号内的运算结果带出来就可以了。
6.最后就是检验完善的时候了,老师的例子的确好,发现了不少的问题,也是花了不少的时间改正了过来。
7.从最初的107行到现在的174行,不停地找bug和可以完善的地方。
8.最后用老师的代码直接自己改了一下,弄了一个小小的美化。
9.有觉着这是一个计算器,于是我又加了一些小小的简化运算,比如开方什么的。
10.本来写的是一个整体的,后来也是在老师的建议下,我还是成了子函数,因为子函数整体的结构比较清晰明了。
大概的思路就是上面那个了,之后的调试之类的也是很久,但是主要的框架就只这样做出来的。
程序结构图:
文字演示:
输入:3-4*(8-5)
第一步:找到括号,运算出括号内为3。
第二步:扫描括号外数字扫描到括号就直接当做3,并跳过,式子变为:3-4*3。
第三布:就直接运算3-4*3=-9。输出,结束。
表1.子函数:
数值类型 | 名字 | 作用描述 |
void | NUMchucun | 括号内录入 |
void | KUOjisuan | 括号内运算结果 |
void | shu | 括号外的数字的存储 |
void | cheng | 整个的乘法运算 |
void | jiafa | 最后的加减的运算 |
void | jiancha | 检查式子有无错误 |
表2.数组:
数据类型 | 名字 | 描述 |
char | mula | 用户输入的运算式 |
double | KUOSUM | 每个括号的所有数的运算结果 |
double | KUONUM | 括号内的所有的数 |
double | KUOSEA | 括号内的乘法和除法的运算结果 |
double | KUO | 括号在字符串内的位置 |
double | NUM | 非括号的其他数字 |
double | SEA | 非括号的其他数字的乘法和除法的运算结果 |
double | num | 将char类型装换的存放的一个数组,不参加主要运算 |
(三) 用户手册
1.当程序运行时,会提示你输入。
2.只能输入数字,加减乘除,括号,和规定的特殊运算代号。
警告:输入其他的字符将会终止程序。
(六)进一步改进
(1).目前这个程序不支持空格的处理,但是可以考虑用getchar来进行一个一个的输入扫描排出。
(七)心得体会:
问题:
1.定义的int型,导致4/5的时候输出结果为0,发现之后先就是将程序的所有
数组改为了double型,然后将关键的变量也修改为double,ok了。
2. 无法计算4+5*1-6,原因是在前面没有+或者-的时候,存储的算式中的数值没办法进位,所以进行运算的就是零了,加入了判断,让。
3. 4*5-4,这个算式之前会遇到一个bug,因为在*之前的运算符号里面并没有+-这两种中的一个,所以的算式在看到这个式子的时候就会直接将后面的4给变为0,这样的话我们的算式就直接变成了4*5-0.这样肯定是错的,所以我增加了一个代码行,写入一个如果前面没有加号和减号,也会计算一个变量。
心得:
首先肯定是自己的编程能力得到了很大的提高,在对待问题的严谨程度上也有了很大的提升,在编程中找到快乐是走得更远的一大前提,而这次最美的就是在最无助的时候坚持。一开始写的时候想的是2天写出来,因为一开始就得很简单嘛,但是写着写着就不对了,慢慢觉得好多东西都对,一个一个的bug出来,白天也想晚上也想,就这样过了整整4天的样子,终于把一个大概的成品写出来了,当时写出的时候真的是觉得值了,之前的努力都没白费,简直爽。慢慢的自己也是喜欢上了编程,他不像其他东西,有可能出错,他特别严谨,只有你错了,没有它错了。
建议:
感觉的话就是题目太少了,这样很大的限制了同学的发挥,就是可不可以试一试让同学自己随便写然后根据难易创意来打分。
源代码:
#include<iostream>
#include<math.h>
#include<vector>
#include"ConsoleOut.h"
#pragmacomment (lib, "ConsoleOut.lib")
usingnamespace std;
#defineSize 10000
#definePI 3.1415926
voidNUMchucun(double[],int,char[],double[],double[]);//括号内录入函数的声明
voidKUOjisuan(double[],int,double[],char[],double[],double[]);//括号内运算结果函数声明
voidshu(int,char[],double[],double[],double[],double[]);//括号外的数字的存储函数声明
voidcheng(int,double[],char[],double[],double[],int[]);//整个的乘法运算函数声明
voidjiafa(int,double[],char[],double[],double[]);//最后的加减的运算函数声明
voidjiancha(char[],int,int,int[]);
voidgraph_welcome(void)
{
CreateSmWindow(0,0, 75,23, 12, 0, 2, 1,"Super Counter", false);
MoveCursorTo(2, 1);
SetTextColor(12, 1);
}
//主程序代码
intmain()
{
op:
int weizi=4;
graph_welcome();
char mula[Size];//用户输入的运算式
cout<<"使用说明:1.式子前面加“s,c,t”可以执行正弦余弦正切。";
MoveCursorTo(2, 2);
cout<<" 2.式子前面加“:”可以执行开方。";
MoveCursorTo(2, 3);
while(cin>>mula)
{
double teshu[1]={0};//专门用来当特殊数
int teshu1[1]={0};//专门当特殊数
int error[1]={0};
double KUOSUM[Size]={0};//每个括号的所有数的运算结果
double KUONUM[Size]={0};//括号内的所有的数
double KUOSEA[Size]={0};//括号内的乘法和除法的运算结果
double KUO[Size]={0};//括号在字符串内的位置
double NUM[Size]={0};//非括号的其他数字
double SEA[Size]={0};//非括号的其他数字的乘法和除法的运算结果
double num[Size]={0};//将char类型装换的存放的一个数组,不参加主要运算
double sum=0,DX=0;
int n=0,i=0,kuo=0;
n=strlen(mula);//计算输入的长度
mula[n]=',';//在最后一位后加一个P
jiancha(mula,n,weizi,error);
if(error[0]){weizi+=1;goto over1;}
for(i=0;i<=n;i++)//找到括号的位置
{
if(mula[i]=='('||mula[i]==')'){KUO[kuo]=i;kuo++;}
}
NUMchucun(KUO,kuo,mula,KUONUM,num);//将每个括号内的数单独给存储出来
KUOjisuan(KUONUM,kuo,KUO,mula,KUOSEA,KUOSUM);//将括号内的运算结果储存到KUOSUM这个数组里面
shu(n,mula,num,NUM,KUO,KUOSUM);//扫描非括号内的数字储存
cheng(n,KUO,mula,SEA,NUM, teshu1);//算式的乘法
jiafa(n,NUM,mula,SEA,teshu);//算式的加减
for(i=0;i<=teshu1[0];i++){teshu[0]+=SEA[i];}//为了保险进行一个加减
MoveCursorTo(2, weizi);
weizi+=1;
if(mula[0]==':'){teshu[0]=sqrt(teshu[0]);}//求开方
if(mula[0]=='s'){teshu[0]=teshu[0]/180*PI;teshu[0]=sin(teshu[0]);}//求sin
if(mula[0]=='c'){teshu[0]=teshu[0]/180*PI;teshu[0]=cos(teshu[0]);}//求cos
if(mula[0]=='t'){teshu[0]=teshu[0]/180*PI;teshu[0]=tan(teshu[0]);}//求tan
cout<<teshu[0]<<endl;//输出
over1:
MoveCursorTo(2, weizi);//移动光标
weizi+=1;
cout<<"------------------------------";
MoveCursorTo(2, weizi);
if(weizi==24){goto op;}//限制不出方格
weizi+=1;
}
return 0;
}
voidjiancha(char*mula,int n,int weizi,int*error)
{
for(inti=1;i<n;i++)//判断输入的算式有没有错误
{
if(mula[i]<39||mula[i]==44||mula[i]>58)
{
MoveCursorTo(2,weizi);cout<<"!!算式错误"<<endl;//输出错误
weizi+=1;error[0]+=1;gotoover;//终止程序
}
if(mula[i]=='+'||mula[i]=='-'||mula[i]=='*'||mula[i]=='/')
{
if(mula[i+1]=='+'||mula[i+1]=='-'||mula[i+1]=='*'||mula[i+1]=='/'||mula[i+1]=='=')
{
MoveCursorTo(2,weizi);cout<<"!!算式错误"<<endl;//输出错误
weizi+=1;error[0]+=1;gotoover;//终止程序
}
}
}
over:;
}
//录入数字的子函数
voidNUMchucun(double*KUO,int kuo,char*mula,double*KUONUM,double*num)
{
intx=0,in=0,i=0,peak=0,l=0,y=0,g=0,wwe=0,ww=0;
for(x;x<=kuo/2;x++)
{
i=KUO[in]+1;
for(i;i<=KUO[in+1];i++)
{
if(mula[i]=='.')//判断是否为带小数点的
{
ww=i;
for(ww;ww<=KUO[in+1];ww++)//循环存储小数点后几位的函数
{
if(mula[ww]>47&&mula[ww]<58){num[peak]=mula[ww]-48;peak++;i++;}
if(mula[ww]=='+'||mula[ww]=='-'||mula[ww]=='*'||mula[ww]=='/'||mula[ww]==','||mula[ww]==')'){gotonike;}
}
}
if(mula[i]>47&&mula[i]<58){num[peak]=mula[i]-48;peak++;l++;}//录入小数点前几位
if(mula[i]=='+'||mula[i]=='-'||mula[i]=='*'||mula[i]=='/'||mula[i]==','||mula[i]==')')//开始总结存入数字
{
wwe=l;
for(y=0;y<peak;y++)
{
KUONUM[g]=num[y]*pow(10,l-1)+KUONUM[g];
l--;
}
// l=0;
g++;
peak=0;
}
nike:;
}
in+=2;
}
}
//括号内运算结果函数
voidKUOjisuan(double*KUONUM,intkuo,double*KUO,char*mula,double*KUOSEA,double*KUOSUM)
{
int x=0, in=0,q=0,i=0,sea=0,nike=0;
double DX=0,sum=0;
DX=KUONUM[0];//先将DX赋第一个括号的第一个数
for(x;x<kuo/2;x++)//计算括号内的运算结果
{
i=KUO[in]+1;
for(i;i<KUO[in+1];i++)//乘除的运算结果
{
if(mula[i]=='+'||mula[i]=='-'){q++;DX=KUONUM[q];sea++;}
if(mula[i]=='*'){DX=DX*KUONUM[q+1];KUONUM[q+1]=0;KUONUM[q]=0;q++;KUOSEA[sea]=DX;}
if(mula[i]=='/'){DX=DX/KUONUM[q+1];KUONUM[q+1]=0;KUONUM[q]=0;q++;KUOSEA[sea]=DX;}
}
q=0;sum=KUONUM[0];
i=KUO[in]+1;
for(i;i<KUO[in+1];i++)//加减
{
if(mula[i]=='+'||mula[i]=='*'||mula[i]=='/'){sum+=KUONUM[q+1];q++;}
if(mula[i]=='-'){sum-=KUONUM[q+1];q++;}
}
for(i=0;i<=sea;i++){sum+=KUOSEA[i];}//算出结果
KUOSUM[x]=sum;//给KUOSUM这个数组
in+=2;
nike+=(KUO[x+1]-KUO[x])/2;
DX=KUONUM[nike];//又将DX赋于第二个括号内的第一个数
}
}
//括号外的数字的存储函数
voidshu(int n,char*mula,double*num,double*NUM,double*KUO,double*KUOSUM)
{
int i=0,x=0,l=0,y=0,in=0,yun=0,g=0,ww=0;
for(i;i<=n;i++)//开始扫描出非括号内的数
{
if(mula[i]=='.')//
{
ww=i;
for(ww;ww<=n;ww++)
{
if(mula[ww]>47&&mula[ww]<58){num[x]=mula[ww]-48;x++;i++;}
if(mula[ww]=='+'||mula[ww]=='-'||mula[ww]=='*'||mula[ww]=='/'||mula[ww]==','||mula[ww]==')'){gotonike;}
}
}
if(mula[i]>47&&mula[i]<58){num[x]=mula[i]-48;x++;l++;}
if(mula[i]=='+'||mula[i]=='-'||mula[i]=='*'||mula[i]=='/'||mula[i]==',')
{
for(y=0;y<x;y++)
{
NUM[g]=num[y]*pow(10,l-1)+NUM[g];
l--;
}
l=0;
g++;
x=0;
}
if(mula[i]=='('){NUM[g]=KUOSUM[yun];i=KUO[in+1];in++;yun++;g++;}//扫描到括号的时候就插入之前的运算数,并跳过
nike:;
}
}
//整个的乘法运算函数
voidcheng(int n,double*KUO,char*mula,double*SEA,double*NUM,int*teshu1)
{
int in=0,i=0,q=0;
teshu1[0]=0;
double DX=NUM[0];
for(i=0;i<n;i++)//运算括号外的的乘除运算结果
{
if(mula[i]=='('){i=KUO[in+1];in++;}
if(mula[i]=='+'||mula[i]=='-'){q++;DX=NUM[q];if(SEA[teshu1[0]]!=0){teshu1[0]+=1;}}//如果第一个是没有赋值的话就不sea++
if(mula[i]=='*'){DX=DX*NUM[q+1];NUM[q+1]=0;NUM[q]=0;q++;SEA[teshu1[0]]=DX;}
if(mula[i]=='/'){DX=DX/NUM[q+1];NUM[q+1]=0;NUM[q]=0;q++;SEA[teshu1[0]]=DX;}
}
}
//最后的加减的运算函数
voidjiafa(int n,double*NUM,char*mula,double*SEA,double*teshu)//算式的加减
{
int q=0,i=0,adidas=0,over=0;
teshu[0]=NUM[0];
for(i=0;i<n;i++)//扫描过去
{
if(mula[i]=='+')
{
for(adidas=i+1;adidas<=n;adidas++)//为了防止一个bug(PS:2-3*4)比如括号这个,减法的话会执行减去的是我
{ //已经归零的3,而不是这个整式子,然后就会子
if(mula[adidas]=='*'||mula[adidas]=='/'){teshu[0]+=SEA[over];SEA[over]=0;over++;q++;gotoloop;}
if(mula[adidas]=='+'||mula[adidas]=='-'||mula[adidas]==','||mula[adidas]=='('){teshu[0]+=NUM[q+1];q++;gotoloop;}
}
}
if(mula[i]=='-')
{
for(adidas=i+1;adidas<=n;adidas++)
{
if(mula[adidas]=='*'||mula[adidas]=='/'){teshu[0]-=SEA[over];SEA[over]=0;over++;q++;gotolop;}
if(mula[adidas]=='+'||mula[adidas]=='-'||mula[adidas]==','||mula[adidas]=='('){teshu[0]-=NUM[q+1];q++;gotolop;}
}
}
if(mula[i]=='*'||mula[i]=='/'){q++;}//如果为了防止一个bug(PS:3*4-5),因为前面没有+或者-。
loop:lop:; //所以不会执行q++然后就么办法执行到-5的命令,而是执行-4,
} //但是4在我前一个步就归零了,所以错误
}