其实这是去年写的程序了,一个很简陋的程序。
去年上数据结构,老师让我们自己选题写一个程序。那个时候刚学完后缀表达式,本来打算把书本上介绍的计算后缀表达式的程序实现出来,后来觉得太不形象,就想干脆做一个计算器的样子出来吧,当时还不会写GUI,所以就在控制台写了一个“伪GUI”,虽然丑了点,但是还是确实可以用的。
开发环境:Windows 8.1 — CodeBlocks13.12
先把整个代码的框架传上来:
再简单介绍一下各个源文件的作用:
文件名 | 作用 |
---|---|
Caculate1.0.cpp | 1:读取原始表达式 2:整理表达式 3:运行计算器 |
Check.cpp | 检查各种操作以及表达式的合法性 |
GetAnswer.cpp | 根据后缀表达式求得表达式的值 |
GetPostfix.cpp | 将用户的输入转化为后缀表达式 |
main.cpp | 主调函数 |
SetUI.cpp | 设置计算器的界面 |
头文件中放置的是各个源文件所需要的头文件以及函数声明和数据定义
依次如下:
Base.h
#ifndef _BASE_H
#define _BASE_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif // _BASE_H
Caculate1.0.h
#ifndef _CACULATE_1_0_H
#define _CACULATE_1_0_H
#include "Base.h"
#include "SetUI.h"
void Run_Caculate(); ///运行计算器
string GetInput(); ///获取原始表达式
string sort_Expression(string Expression); ///整理表达式
#endif //_CACULATE_1.0_H
Check.h
#ifndef _CHECK_H
#define _CHECK_H
#include "Base.h"
#include "Caculate1.0.h"
bool Check(string &Expression); ///检查表达式是否合法
bool Check_Bracket(string Expression); ///检查括号配对
bool Check_Operator(string Expression); ///检查运算符
bool Check_Point(string Expression); ///检查小数点
bool is_op_1(char temp); ///判断是不是加减乘除
#endif // _CHECK_H
GetAnswer.h
#ifndef _GET_ANSWER_H
#define _GET_ANSWER_H
#include "Base.h"
#include "GetPostfix.h"
string GetAnswer(string Postfix);
#endif
GetPostfix.h
#ifndef _GET_POSTFIX_H
#define _GET_POSTFIX_H
#include "Base.h"
#include "Caculate1.0.h"
#include "SetUI.h"
#include "Check.h"
string GetPostfix(string Expression); ///获取后缀表达式
bool precede(char op1, char op2);
#endif // _GET_POSTFIX_H
SetUI.h
#ifndef _SETUI_H
#define _SETUI_H
#include "Base.h"
using namespace std;
void SetUI(); ///设置界面
void SetFrame(); ///设置边框
void SetButton(); ///设置按键
void gotoxy(int x, int y); ///跳转光标位置
#endif // _SETUI_H
从main函数开始:
#include
#include "Base.h"
#include "SetUI.h"
#include "Caculate1.0.h"
using namespace std;
int main()
{
while(true){
SetUI(); ///设置界面
Run_Caculate(); ///运行计算器
getch(); ///一次运行完之后暂停
gotoxy(0, 0); ///光标位置复位
}
return 0;
}
首先生成一个UI界面:
SetUI.cpp
#include "SetUI.h"
#include "Base.h"
using namespace std;
void gotoxy(int x, int y){
HANDLE app;
COORD POS;
POS.X = x;
POS.Y = y;
app = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(app, POS);
}
void SetUI(){ ///设置界面
SetConsoleTitle("计算器-----by廖小鑫"); ///设置窗口标题
// HANDLE Hinput = GetStdHandle(STD_INPUT_HANDLE); ///设置输入句柄
HANDLE Houtput = GetStdHandle(STD_OUTPUT_HANDLE); ///设置输出句柄
SMALL_RECT rc = {0, 0, 2 * (17 + 1) + 1, 26 + 3};
SetConsoleWindowInfo(Houtput, true, &rc); ///设置窗口大小
CONSOLE_CURSOR_INFO curInfo; ///光标信息设置
curInfo.dwSize = 1; ///光标厚度
curInfo.bVisible = 0; ///光标是否可见
SetConsoleCursorInfo(Houtput, &curInfo); ///设置光标信息
SetFrame();
SetButton();
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_RED |FOREGROUND_INTENSITY);
}
void SetFrame(){ ///设置边框
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE |FOREGROUND_INTENSITY);
printf("■■■■■■■■■■■■■■■■■■■\n");
for(int i = 1; i < 27; i++){
printf("■\t\t\t\t ■\n");
}
printf("■■■■■■■■■■■■■■■■■■■\n");
gotoxy(2, 5);
printf("■■■■■■■■■■■■■■■■■");
};
void SetButton(){ ///设置按键
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 10);
for(int i = 0; i < 5; i++){
for(int j = 0 ; j < 4; j++){
gotoxy(4 + j * 8, 7 + 4 * i);
for(int m = 0; m < 3; m++){
for(int n = 0; n < 3; n++){
printf("■");
}
gotoxy(4 + j * 8, 7 + 4 * i + m + 1);
}
}
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
gotoxy(6, 8);
printf("+");
gotoxy(14, 8);
printf("-");
gotoxy(22, 8);
printf("*");
gotoxy(30, 8);
printf("/");
gotoxy(6, 12);
printf("7");
gotoxy(14, 12);
printf("8");
gotoxy(22, 12);
printf("9");
gotoxy(30, 12);
printf("Cl");
gotoxy(6, 16);
printf("4");
gotoxy(14, 16);
printf("5");
gotoxy(22, 16);
printf("6");
gotoxy(30, 16);
printf("←");
gotoxy(6, 20);
printf("1");
gotoxy(14, 20);
printf("2");
gotoxy(22, 20);
printf("3");
gotoxy(30, 20);
printf("=");
gotoxy(6, 24);
printf(".");
gotoxy(14, 24);
printf("0");
gotoxy(22, 24);
printf("(");
gotoxy(30, 24);
printf(")");
};
然后运行计算器:
完成以下几件事
1:读取输入
2:将输入的中缀式转化成后缀表达式
#include "Caculate1.0.h"
#include "Base.h"
#include "SetUI.h"
#include "Check.h"
#include "GetPostfix.h"
#include "GetAnswer.h"
using namespace std;
void Run_Caculate(){ ///运行计算器
string Expression = ""; ///原始表达式初始化为空串
Expression = GetInput(); ///读取原始表达式
gotoxy(4, 3); ///跳到输出位置
cout << "="; ///输出等号
if(Check(Expression) == true){ ///表达式括号、运算符合法
Expression = sort_Expression(Expression); ///整理表达式
if(Check_Point(Expression)){ ///小数点合法
string Postfix = GetPostfix(Expression);
string Answer = GetAnswer(Postfix);
if(Answer == "ERROR!"){
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
cout << "Devied zero!" << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
}
else{
double temp = atof(Answer.c_str());
cout << temp;
}
}
else{ ///表达式不合法
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
cout << "Too Many Decimal Point!" << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
}
}
else{ ///表达式不合法
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 12);
cout << "ERROR!" << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 14);
}
return ;
}
string GetInput(){ ///读取原始表达式
string Expression = ""; ///原始表达式初始化为空串
HANDLE Hinput = GetStdHandle(STD_INPUT_HANDLE);
HANDLE Houtput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO bInfo;
INPUT_RECORD mouseRec;
DWORD res;
COORD Pos = {0, 0};
bool mark = 1; ///为真读取输入
int curX = 4; ///输出的x坐标位置
while(mark == 1){ ///读取鼠标输入
gotoxy(curX, 2); ///跳到输出表达式的位置
ReadConsoleInput(Hinput, &mouseRec, 1, &res); ///读取控制台输入
if(mouseRec.EventType == MOUSE_EVENT){ ///是鼠标类型输入
Pos = mouseRec.Event.MouseEvent.dwMousePosition; ///获取当前鼠标位置
GetConsoleScreenBufferInfo(Houtput, &bInfo);
if(mouseRec.Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED){ ///鼠标左键单击事件
if(Pos.X >= 4 && Pos.X <= 33 && Pos.Y >= 7 && Pos.Y <= 25){ ///鼠标输入在按钮区内
switch((Pos.X - 4) / 8){ ///外层switch列举不同列的按钮
case 0:{
if(Pos.X <= 9){
switch((Pos.Y - 7) / 4){ ///内层switch列举不同行的按钮
case 0:{
if(Pos.Y <= 9){
Expression += "+";
printf("+");
curX++;
}
break;
}
case 1:{
if(Pos.Y <= 13){
Expression += "7";
printf("7");
curX++;
}
break;
}
case 2:{
if(Pos.Y <= 17){
Expression += "4";
printf("4");
curX++;
}
break;
}
case 3:{
if(Pos.Y <= 21){
Expression += "1";
printf("1");
curX++;
}
break;
}
case 4:{
if(Pos.Y <= 25){
Expression += ".";
printf(".");
curX++;
}
break;
}
}
}
break;
}
case 1:{
if(Pos.X <= 17){
switch((Pos.Y - 7) / 4){
case 0:{
if(Pos.Y <= 9){
Expression += "-";
printf("-");
curX++;
}
break;
}
case 1:{
if(Pos.Y <= 13){
Expression += "8";
printf("8");
curX++;
}
break;
}
case 2:{
if(Pos.Y <= 17){
Expression += "5";
printf("5");
curX++;
}
break;
}
case 3:{
if(Pos.Y <= 21){
Expression += "2";
printf("2");
curX++;
}
break;
}
case 4:{
if(Pos.Y <= 25){
Expression += "0";
printf("0");
curX++;
}
break;
}
}
}
break;
}
case 2:{
if(Pos.X <= 25){
switch((Pos.Y - 7) / 4){
case 0:{
if(Pos.Y <= 9){
Expression += "*";
printf("*");
curX++;
}
break;
}
case 1:{
if(Pos.Y <= 13){
Expression += "9";
printf("9");
curX++;
}
break;
}
case 2:{
if(Pos.Y <= 17){
Expression += "6";
printf("6");
curX++;
}
break;
}
case 3:{
if(Pos.Y <= 21){
Expression += "3";
printf("3");
curX++;
}
break;
}
case 4:{
if(Pos.Y <= 25){
Expression += "(";
printf("(");
curX++;
}
break;
}
}
}
break;
}
case 3:{
if(Pos.X <= 33){
switch((Pos.Y - 7) / 4){
case 0:{
if(Pos.Y <= 9){
Expression += "/";
printf("/");
curX++;
}
break;
}
case 1:{ ///清除所有数据,重新开始
if(Pos.Y <= 13){
curX = 4;
gotoxy(0, 0);
SetUI();
mark = 0;
}
break;
}
case 2:{ ///退一个字符
if(Pos.Y <= 17){
if(curX >= 5){
Expression = Expression.substr(0, Expression.size() - 1);
printf("\b \b");
curX--;
}
}
break;
}
case 3:{ //等于号
if(Pos.Y <= 21){
mark = 0;
}
break;
}
case 4:{
if(Pos.Y <= 25){
Expression += ")";
printf(")");
curX++;
}
break;
}
}
}
break;
}
}
}
}
}
}
// cout << "asas" << Expression << endl;
return Expression;
}
string sort_Expression(string Expression){ ///整理表达式
string Sorted_Expression = "";
unsigned n = 0;
if(Expression[n] == '-'){
Sorted_Expression += "(0-";
n++; ///指向第一个数的第一个数码
while((Expression[n] >= '0' && Expression[n] <= '9') || Expression[n] == '.'){
Sorted_Expression += Expression[n];
n++;
} ///n指向运算符
Sorted_Expression += ")";
}
else{
while((Expression[n] >= '0' && Expression[n] <= '9') || Expression[n] == '.'){
Sorted_Expression += Expression[n];
n++;
} ///n指向运算符
}
for(unsigned int i = n; i < Expression.size(); ){
Sorted_Expression += Expression[i]; ///加上运算符
i++;
if(Expression[i] == '-' && Expression[i - 1] != ')'){
Sorted_Expression += "(0-";
i++; ///指向第一个数的第一个数码
while((Expression[i] >= '0' && Expression[i] <= '9') || Expression[i] == '.'){
Sorted_Expression += Expression[i];
i++;
} ///指向一个新的运算符
Sorted_Expression += ")";
}
else if(Expression[i] != '('){
while((Expression[i] >= '0' && Expression[i] <= '9') || Expression[i] == '.'){
Sorted_Expression += Expression[i];
i++;
}
}
}
// cout << Sorted_Expression << endl;
// cout << Sorted_Expression.size() <
return Sorted_Expression;
}
检查合法性:
#include "Check.h"
#include
using namespace std;
bool is_op_1(char temp){ ///检查是不是加减乘除
if(temp == '+' || temp == '-' || temp == '*' || temp == '/'){
return true;
}
else{
return false;
}
}
bool Check(string &Expression){ ///检查表达式是否合法
if(Check_Bracket(Expression) && ///检查括号配对情况
Check_Operator(Expression) ///检查运算符合法情况
){
return true;
}
else{
return false;
}
}
bool Check_Bracket(string Expression){ ///检查括号配对情况
stack<char>S;
bool mark = 1; ///先默认合法
for(unsigned int i = 0; i < Expression.size(); i++){
if(Expression[i] == '('){ ///左括号一律入栈
S.push('(');
}
else if(Expression[i] == ')'){ ///右括号
if(!S.empty() && S.top() == '('){
S.pop();
}
else{
mark = 0;
break;
}
}
}
if(mark == 1 && S.empty()){
return true;
}
else{
return false;
}
}
bool Check_Operator(string Expression){ ///检查运算符合法情况
int count_op = 0;
bool mark = 1;
for(unsigned int i = 0; i < Expression.size(); i++){
if(is_op_1(Expression[i])){ ///是加减乘除
count_op++;
}
else{
count_op = 0;
}
if(count_op == 1 && (i + 1) < Expression.size() && (i - 1) >= 0 &&
(Expression[i + 1] == ')' || ( Expression[i - 1] == '(' && Expression[i] != '-'))){
mark = 0;
break;
}
if((count_op == 2 && Expression[i] != '-') || count_op == 3){ ///不合法
mark = 0;
break;
}
}
if(is_op_1(Expression[Expression.size() - 1])){ ///末尾不能是运算符
mark = 0;
}
if(mark == 1){
return true;
}
else{
return false;
}
}
bool Check_Point(string Expression){ ///检查小数点合法情况
int count_num = 0;
bool mark = 1;
for(unsigned int i = 0; i < Expression.size(); i++){
if(Expression[i] == '(' || Expression[i] == ')' || is_op_1(Expression[i])){
count_num = 0;
continue;
}
else{
if(Expression[i] == '.'){
count_num++;
if(count_num >= 2){
mark = 0;
break;
}
}
}
}
if(mark == 1){
return true;
}
else{
return false;
}
}
根据中缀式获取后缀表达式:
#include "GetPostfix.h"
#include "Check.h"
using namespace std;
char op[10] = {'#','(','+','-',')','*','/'}; ///运算符优先级
int priority_op[10] = {-1, 0, 1, 1, 2, 2, 2};
bool precede(char op1, char op2){ ///第一个参数的优先级大于等于第二个时返回真
int temp1, temp2;
for(int i = 0; i < 7; i++){
if(op1 == op[i]){
temp1 = priority_op[i];
}
if(op2 == op[i]){
temp2 = priority_op[i];
}
}
if(temp1 >= temp2){
return true;
}
else{
return false;
}
}
string GetPostfix(string Expression){
string Postfix = "";
stack<char>S;
S.push('#');
for(unsigned int i = 0; i < Expression.size(); i++){
if(!is_op_1(Expression[i]) &&
Expression[i] != '(' && Expression[i] != ')'){ ///是数字
Postfix += 'S'; ///加一个起始标记
do{ ///把这个数字加完
Postfix += Expression[i];
i++;
}while(!is_op_1(Expression[i]) &&
Expression[i] != '(' && Expression[i] != ')' &&
i < Expression.size());
Postfix += 'E';
i--; ///指向当前数字的最后一个字符
}
else{
printf(" \b");
switch(Expression[i]){
case '(':{ ///前括号一律入栈
S.push('(');
break;
}
case ')':{ ///遇到右括弧就把左括弧之前的发给后缀式
do{
Postfix += S.top();
S.pop();
}while(S.top() != '(');
S.pop();
break;
}
default:{
while(precede(S.top(), Expression[i])){
Postfix += S.top();
S.pop();
}
S.push(Expression[i]);
break;
}
}
}
}
while(S.top() != '#'){
Postfix += S.top();
S.pop();
}
return Postfix;
}
根据后缀表达式计算最终的答案:
#include "GetAnswer.h"
#include "Base.h"
using namespace std;
string GetAnswer(string Postfix){
string Answer;
stack<double>S;
string temp1_string = "";
double temp1_double;
double temp2_double;
for(unsigned int i = 0; i < Postfix.size(); i++){
if(Postfix[i] == 'S'){ ///入栈了一个数字
i++;
temp1_string = "";
while(Postfix[i] != 'E'){
temp1_string += Postfix[i];
i++;
}
temp1_double = atof(temp1_string.c_str());
S.push(temp1_double);
}
else{ ///指向操作符
temp1_double = S.top();S.pop();
temp2_double = S.top();S.pop();
switch(Postfix[i]){
case '+':{
temp1_double = temp1_double + temp2_double;
S.push(temp1_double);
break;
}
case '-':{
temp1_double = temp2_double - temp1_double;
S.push(temp1_double);
break;
}
case '*':{
temp1_double = temp1_double * temp2_double;
S.push(temp1_double);
break;
}
case '/':{
if(temp1_double == 0){
return Answer = "ERROR!";
}
else{
temp1_double = temp2_double / temp1_double;
S.push(temp1_double);
}
break;
}
}
}
}
char buffer[256];
sprintf(buffer, "%f", S.top());
Answer = buffer;
// cout << Answer << endl;
return Answer;
}
使用手册:
1:使用时用鼠标单击控制台窗口上的虚拟按键即可输入,如果进行了错误输入,可以点击计算器的“←”按钮删除前一个输入。
2:表达式输入完成后鼠标左键单击“=”按钮即可计算出结果并显示在屏幕上。
3:一次计算结束后,按键盘上的任意键可继续进行下次计算。
4:该计算器可进行表达式合法性判断:
①:括号不匹配,报错 ERROE!
②:运算符不符合数学运算规则,报错 ERROR!
③:单个数字小数点超过1个,报错 Too Many Decimal Point!
④:表达式中出现除以零的式子,报错 Devied zero!
5:该计算器可以处理带有小数(如3.123 * 3.67)、负数(如-2 + -999)、整数、正数的运算
由于最近没有太多时间,而且代码已经写了一年,印象已经有些松散,回头我找个时间再对这个程序加以详解的介绍说明吧。