项目——简易计算器
来源:互联网 发布:安卓手机编程软件 编辑:程序博客网 时间:2024/06/03 19:37
2017.12.21
决定做一个小项目来练练手了,对期末考试感到无所畏惧。
先选择简易计算器吧,核心算法中缀转后缀表达式我还是学过的,最起码能克服一点心里畏惧。
项目预期如下:
1. 实现命令行版本的核心算法,做简单的加减乘除就可以了;
2. 实现图形化窗口。
代码预期要200行以上.
对自己提一个要求:可以上网找思路,但是绝对不看别人的源码。
2017.12.23
经过几天的努力,总算把这个计算器的核心代码写出来了。代码接近200行,主要利用二重字符串来实现核心的逆波兰算法,实在是有点繁杂。
这段代码实在不堪一看,各种结构体、变量、函数的命名随心所欲,特别是我在操作栈的时候没有专门写几个函数来执行,因为实在不好分类,显得有点繁杂。这也说明了我这种思路局限性太大,代码复用率不高。
但毕竟是自己做出来的,发上来见证一下。编辑器用的是VS2017,有些函数会有些奇怪。另外,结果是浮点型,要保证在6位数以内才绝对正确,不然会有取舍。
// 简易计算器.cpp: 定义控制台应用程序的入口点。// 2017.12.23#include "stdafx.h"#include <iostream>#include <cstdio>#include <conio.h>#include <cstdlib>using namespace std;#define MaxSize 100// 定义数据栈,储存转化为后缀表达式的字符串算式typedef struct Data_SNode { int Top; int Ptr; char Elem[MaxSize][MaxSize];} *D_Stack;// 定义操作符栈,用于执行中缀转后缀表达式typedef struct Operation_SNode { int Top; char Elem[MaxSize];} *Oper_Stack;// 定义算式栈,用于执行后缀表达式的计算typedef struct Counter_SNode { int Top; double Elem[MaxSize];} *C_Stack;D_Stack initData(); // 初始化数据栈Oper_Stack initOper(); // 初始化操作符栈C_Stack initCounter(); // 初始化算式栈void getInput(D_Stack Data, Oper_Stack Oper); // 接受输入算式并储存在数据栈中void PreToSuf(char ch, Oper_Stack Oper, D_Stack Data); // 操作符中缀转后缀表达式算法,即逆波兰核心算法void Count(D_Stack Data, C_Stack Counter); // 计算后缀表达式int main(){ D_Stack Data = initData(); Oper_Stack Oper = initOper(); C_Stack Counter = initCounter(); getInput(Data, Oper); Count(Data, Counter); return 0;}D_Stack initData(){ int i, j; D_Stack Data; Data = (struct Data_SNode *)malloc(sizeof(struct Data_SNode)); for (i = 0; i < MaxSize; i++) { for (j = 0; j < MaxSize; j++) { Data->Elem[i][j] = '\0'; } } Data->Top = -1; Data->Ptr = -1; return Data;}Oper_Stack initOper(){ int i; Oper_Stack Oper; Oper = (struct Operation_SNode *)malloc(sizeof(struct Operation_SNode)); for (i = 0; i < MaxSize; i++) { Oper->Elem[i] = '\0'; } Oper->Top = -1; return Oper;}C_Stack initCounter(){ int i; C_Stack Counter; Counter = (struct Counter_SNode *)malloc(sizeof(struct Counter_SNode)); for (i = 0; i < MaxSize; i++) { Counter->Elem[i] = 65535; } Counter->Top = -1; return Counter;}void getInput(D_Stack Data, Oper_Stack Oper){ int flag; // 标记之前的输入是什么 char ch; // 接收输入字符 flag = 0; // flag:0是初始状态,1代表上一次输入数字,2代表上一次输入符号 ch = _getche(); while (ch != 61) // 在输入‘=’之前 { if (ch >= 48 && ch <= 57) // 如果输入字符是数字,直接存入 { if( flag == 0) // 初始字符 { Data->Elem[++Data->Top][++Data->Ptr] = ch; flag = 1; } else if (flag == 1) // 前一个输入为数字,继续向后排 { Data->Elem[Data->Top][++Data->Ptr] = ch; } else // flag == 2 // 前一个输入为操作符,换一行排 { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = ch; flag = 1; } } else if (ch == 42 || ch == 43 || ch == 45 || ch == 47) // 如果接受字符是符号,执行中缀转后缀算法 { PreToSuf(ch, Oper, Data); flag = 2; } ch = _getche(); } while (Oper->Top >= 0) // 输入‘=’后,将操作符栈中的字符全部取出来 { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = Oper->Elem[Oper->Top--]; }}void PreToSuf(char ch, Oper_Stack Oper, D_Stack Data){ if (Oper->Top == -1) // 如果栈空 { Oper->Elem[++Oper->Top] = ch; } else { if (ch == 42 || ch == 47) // 如果接受字符为*或/,则将栈顶的*或/全部排出再存入 { while (Oper->Elem[Oper->Top] == 42 || Oper->Elem[Oper->Top] == 47) { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = Oper->Elem[Oper->Top--]; } Oper->Elem[++Oper->Top] = ch; } else if (ch == 43 || ch == 45) // 如果接受字符为+或-,则将栈清空再存入 { while (Oper->Top >= 0) { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = Oper->Elem[Oper->Top--]; } Oper->Elem[++Oper->Top] = ch; } }}void Count(D_Stack Data, C_Stack Counter){ int i; double Pre, Later, RST; // Pre为前数,Later为后数,RST为结果值 char Operation; // 符号 for (i = 0; i <= Data->Top; i++) { if (Data->Elem[i][0] >= 48) { Counter->Elem[++Counter->Top] = atof(Data->Elem[i]); // atof()将字符类型转化为double类型 } else { Operation = Data->Elem[i][0]; Later = Counter->Elem[Counter->Top--]; Pre = Counter->Elem[Counter->Top--]; switch (Operation) { case 43: RST = Pre + Later; break; // 加 case 45: RST = Pre - Later; break; // 减 case 42: RST = Pre * Later; break; // 乘 case 47: RST = Pre / Later; break; // 除 } Counter->Elem[++Counter->Top] = RST; } } cout << Counter->Elem[Counter->Top];}
2017.12.24
本想今天做个界面的,看了一下EasyX的函数觉得好绝望,这要怎么做,做出来估计代码也得重改过了……然后就四处浏览。
本打算放弃的,毕竟C/C++做图形界面太难了。但是立下的flag怎么能轻易放弃,所以还是继续做吧。今天就是把小数点和括号的功能完善了,这个不是很难。
改动的就是下面两个核心函数,其它的都照旧,挺水的就过去了。
另外,给平安夜还在学代码的自己打call,也给大家祝快。
void getInput(D_Stack Data, Oper_Stack Oper){ int flag; // 标记之前的输入是什么 char ch; // 接收输入字符 flag = 0; // flag:0是初始状态,1代表上一次输入数字,2代表上一次输入符号 ch = _getche(); while (ch != 61) // 在输入‘=’之前 { if (ch >= 48 && ch <= 57 || ch == 46) // 如果输入字符是数字或小数点,直接存入 { if( flag == 0) // 初始字符 { Data->Elem[++Data->Top][++Data->Ptr] = ch; flag = 1; } else if (flag == 1) // 前一个输入为数字,继续向后排 { Data->Elem[Data->Top][++Data->Ptr] = ch; } else // flag == 2 // 前一个输入为操作符,换一行排 { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = ch; flag = 1; } } else if (ch == 42 || ch == 43 || ch == 45 || ch == 47 || ch == 40 || ch == 41) { // 如果接受字符是符号,执行中缀转后缀算法 PreToSuf(ch, Oper, Data); flag = 2; } ch = _getche(); } while (Oper->Top >= 0) // 输入‘=’后,将操作符栈中的字符全部取出来 { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = Oper->Elem[Oper->Top--]; }}void PreToSuf(char ch, Oper_Stack Oper, D_Stack Data){ if (Oper->Top == -1) // 如果栈空 { Oper->Elem[++Oper->Top] = ch; } else { if (ch == 42 || ch == 47) // 如果接受字符为*或/,则将栈顶的*或/全部排出再存入 { while (Oper->Elem[Oper->Top] == 42 || Oper->Elem[Oper->Top] == 47) { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = Oper->Elem[Oper->Top--]; } Oper->Elem[++Oper->Top] = ch; } else if (ch == 43 || ch == 45) // 如果接受字符为+或- { if (Oper->Elem[Oper->Top] == 40) // 栈顶是(,则直接存入 Oper->Elem[++Oper->Top] = ch; else // 栈顶为其他,则取出至栈顶为(或栈空,再存入 { while (Oper->Top >= 0 && Oper->Elem[Oper->Top] != 40) { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = Oper->Elem[Oper->Top--]; } Oper->Elem[++Oper->Top] = ch; } } else if (ch == 40) // 接受字符为(,则直接存入 { Oper->Elem[++Oper->Top] = ch; } else if (ch == 41) // 接受字符为),则将栈内(前字符全部排出,并舍弃( { while (Oper->Elem[Oper->Top] != 40) { Data->Ptr = -1; Data->Elem[++Data->Top][++Data->Ptr] = Oper->Elem[Oper->Top--]; } Oper->Top--; } }}
2017.12.25
上网专门找了别人是如何做图形界面的,发现和我想象中的相去甚远。看了下代码,发现要是想实现点击计算的功能,整个代码得重头开始,但其实核心功能我已经实现了。如果只是想输入计算,那么我现在做的已经差不多达到目的了。再做下去就是如何完善细节,已经优化代码的事情了,所以干脆放弃这个小任务。
想了想还是有点不爽,做了这几天就完成这么一个小玩意,实在没达到目的。既然C/C++图形界面做得这么差劲,实在做不起自己心仪的小项目,那干脆之后学Python吧。
附上找到的图形界面版本的计算器:
http://blog.csdn.net/shu_lance/article/details/51570987
- 项目——简易计算器
- Java—简易计算器
- swift 项目 简易计算器
- 实战——简易计算器
- 简易统计计算器——C++版
- 菜鸟学习Struts——简易计算器
- 寒假刷oj——简易计算器
- 蜗牛—JQuery学习之简易计算器
- 蜗牛—JavaScript学习之简易计算器
- Android入门项目1:简易计算器
- Java实战项目__简易计算器
- QT项目——计算器
- 项目1—个人所得税计算器
- c语言强化训练——简易计算器
- 小刀——基于Android平台的简易计算器
- iPhone应用开发——简易计算器的设计
- Android开发——实现Android简易计算器
- python习作——简易24点计算器
- Kindeditor实现图片上传
- 监督学习
- 简析vector
- 数据结构实验之查找一:二叉排序树
- vue.js脚手架vue-cli的搭建
- 项目——简易计算器
- 4580: [Usaco2016 Open]248
- 跨域问题2
- Android程序的隐藏与退出
- oauth2
- Attention
- Maven的环境隔离
- c# post-get
- Leetcode203. Remove Linked List Elements