原创文章,未经许可禁止转载
mfc计算器运用逆波兰包含四则运算,根号,平方,三角函数,进制转换
计算器是程序猿经典考题,我们学校语言设计课程暑假的任务就是写一个越复杂越好的计算器,一开始在学校里的时候比较忙,断断续续搜了一点资料还是一头雾水,根本不理解怎么利用逆波兰表达式。最近三天请教各路大佬,查阅了不少博客总算是写完了,主要想总结和反思几点。

1、逆波兰究竟怎么写,怎么与mfc关联起来
逆波兰表达式的规则如下:
有两个堆栈,一个是运算符堆栈,另一个是运算数堆栈,从左往右遍历表达式。
1)数字0-9、小数点、pi直接入运算数堆栈。
2) ‘(’ 直接入运算符堆栈。
3)表达式遇到 ‘)’ 将运算符堆栈中的运算符出栈进入运算数堆栈直到’(’ 为止,左右括号直接丢掉。
4)表达式遇到除括号外运算符a,将其与运算符堆栈栈顶运算符b比较优先级
若a>b,直接将a入运算符堆栈,若a<=b,将运算符堆栈中的运算符出栈进入运算数堆栈直到a>运算符堆栈栈顶运算符优先级为止
5)若遍历表达式后,运算符堆栈里仍然有运算符,将其依次入运算数堆栈至栈空。
注意一下的是为了比较优先级,先要在运算符堆栈压入‘=’。我在写这个的时候运算数堆栈采用的是char型数组形式更加方便
核心是先根据上面的规则做一个函数负责将中缀变成后缀压入char*post(我定义的运算数数组),利用一个char型运算符堆栈过渡,然后做一个函数调用另一个函数将post里面的比如‘3’变成3,再利用一个double型堆栈存储数据并进行计算,最后将栈顶double数据返回,利用Format转换成cstring输出

至于如何和mfc关联,我们第一步要建立一个generic class这里CReversePolish作用是将中缀表达式变成后缀表达式并进行计算将cstring类型传给等号输出。

第二步在CCalculatorDlg.cpp里#include“ReversePolish.h”注意没有C,然后在等号处建立类实例调用即可,m_edit是我与编辑框绑定的cstring类型的变量

CReversePolish polish;
m_edit=polish.ReversePolish(m_edit);
UpdateData(false);

2、进制转换怎么做
首先我利用枚举确定当前进制,默认十进制

enum _num {decimal,binary,octal,hex};
_num mynum=decimal;

十进制模块,每个进制最后要确定当前进制,其他进制转成十进制使用strtol(cstring,NULL,进制)(返回类型int)将其他进制数据(cstring表示)转成十进制数据 最后int->cstring
十进制转二进制时
(cstring->int)
char c[20];
_itoa(十进制数据(int类型),c,2);(返回类型void)
再char*->cstring
十进制转八进制和十六进制都可以利用Format见下,至于除十进制间两两相互转换可以先转换成十进制再转换成目标进制。

 void CCalculatorDlg::OnRadio1() //十进制
 {
	if(mynum= =binary) //2->10
	{
		int n=**strtol(m_edit,NULL,2);**
        m_edit.Format("%d",n);
		UpdateData(false);
	}
	if(mynum= =octal) //8->10
	{
		int n=strtol(m_edit,NULL,8);
        m_edit.Format("%d",n);
		UpdateData(false);
	}
	if(mynum= =hex)   //16->10
	{
		int n=strtol(m_edit,NULL,16);
        m_edit.Format("%d",n);
		UpdateData(false);
	}
	**mynum=decimal;**//确定当前进制
}

3、根号,平方,三角函数,ln,lg
这是我不太满意的方面,我只能对结果数字进行运算,而不能在过程进行运算,我采用的方法是对按键直接用cmath头文件

4、关于stack头文件的用法
要写逆波兰首先要学会stack
1)定义 stack< 数据类型 >堆栈名称(mystack);
2)mystack.pop();栈顶数据出栈丢弃(返回类型void)
3)mystack.top();访问栈顶数据(返回类型stack数据类型)
4)mystack.push(数据----同堆栈类型);(返回类型void)
5)mystack.empty();判断堆栈是否为空(返回类型bool)
6)mystack.size();计算堆栈数据数量(返回类型int)

5、关于Format的用法
int等类型的数据可以利用Format函数变成cstring类型数据,例如 cstring m_eidt;
1)int->cstring(显示十进制整数)
int n;
m_edit.Format("%d",n);
2)int->cstring(显示八进制整数)
int n;
m_eidt.Format("%o",n);
3)int->cstring(显示十六进制整数)
int n;
m_edit.Format("%X",n);
4)double->cstring(显示四位小数)
double n;
m_edit.Format(_T("%.4lf"),n);
5)char*->cstring(显示整数)
char c[20];
m_edit.Format("%s",c);
下面是cstring 转int等类型
1)int n=atoi(m_edit);
2)double n=atof(m_edit);

6、报错提示
有三种错误,第一被除数不能为零,第二不能连续两个运算符,第三括号数量要匹配,这里另外做了一个CCheck类在CheckExpression函数(返回不同int值)中对各个问题进行判断,尤其注意括号匹配是通过设置int k=0;遇到左括号k++;遇到右括号k–;最后看k是否为零判断括号数量是否正确。
弹出错误提示框利用的是AfxMessagebox函数

bool flag=true;
m_edit+="=";
CCheck check;//先进行表达式检查
if(check.CheckExpression(m_edit)==1)
{AfxMessageBox("括号不匹配,请重新输入!");m_edit="0";flag=false;}
if(check.CheckExpression(m_edit)==2)
{AfxMessageBox("连续输入两个以上运算符,请重新输入!");m_edit="0";flag=false;}
if(check.CheckExpression(m_edit)==3)
{AfxMessageBox("被除数不能为0,请重新输入!");m_edit="0";flag=false;}
if(flag)
{
CReversePolish polish;
m_edit=polish.ReversePolish(m_edit);
}
UpdateData(false);

还有一种Messagebox函数具体可查看相关文章

7、一些细节
1)我本来打算将‘π’和0-9一样对待压栈,发现经常不能识别,比如按2π直接等于2.0000这种,后来老师说π不在ascii表里,char数组不能容纳,所以后来用 ‘!’ 代替,注意是英文下的感叹号
2)函数里不能定义函数,只能调用函数。
3)vc6.0在两个for循环里不能重定义比如计数值i,要将i设置为全局变量int i; for(i=0……)。
4)除了等号的所有button键只要负责编辑框多一个符号即可,处理都放在逆波兰里。
5)UpdateData(false);作用是刷新当前编辑框显示m_edit的值。
6)j<2*i+1;==不要漏掉 * ==

可算是总结完成第一篇博客,路漫漫其修远兮,还要继续加油

更多推荐

mfc计算器运用逆波兰包含四则运算,根号,平方,三角函数,进制转换