c++计算器后续(3)
自娱自乐:
本来只是想改改第二次的代码规范的,然后好像把原来的代码玩坏了,真是尴尬。。。然后大概是又发现了一些东西。以上。
main的参数:
大概是说main函数的括号里是可以带参数的,写成这个样子:
int main(int argc, char* argv[]),然后这时main函数的输入来自命令行。也就是用cmd直接调用.exe文件时,可以在后面跟上一些数,然后这些数就会被输到main函数里。其中argc表示输入的参数个数,argv则是一个指针数组,指向各个参数,然后argv[0]表示的是.exe文件的路径。写了个简单的代码玩了玩,感觉大概就是这么回事吧。附上代码和调用结果:
#include<iostream>
using namespace std;
int main(int argc, char* argv[])
{
int i = argc;
while (i > 0)
{
cout << argv[argc - i] << endl;
i--;
}
return 0;
}
大概也是因为我这么玩了,然后一不小心把argv数组里的元素当成了字符串,然后我Calculator项目里的main函数写成了这样:
#include<iostream>
#include<queue>
using namespace std;
int main(int argc,char * argv[])
{
Scan CScan;
Print CPrint;
Calculation CCalculate;
string s_input = argv[argc-1]; //输入的字符串
queue<string> qs; //数字和运算符分开的队列
double ans; //四则算式的答案
qs = CScan.ToStringQueue(s_input);
ans = CCalculate.CalculateStringQueue(qs);
if (argv[1] == "-a")
{
CPrint.PrintAns(s_input, ans);
}
else
{
CPrint.PrintAns(ans);
}
return 0;
}
结果当然是cmd里面输入'-a'它也只输出一个答案,然后不幸的还是个错误的答案,啊,这是后话,被我玩坏的代码。
于是又再去看看
int main(int argc,char * argv[]),指向字符的指针,然后就凌乱了,那我前面的输出是什么鬼,不应该输出地址吗,你输出元素也不该是字符串啊。然后就写了一些东西来试试看:
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
string str;
cin >> str;
char* p1 = &str[0];
printf("%x\n",p1);
cout << p1 << endl;
cout << *p1 << endl;
cout << "==分割线==" << endl;
char** p2 = &p1;
printf("%x\n",p2);
cout << p2 << endl;
cout << *p2 << endl;
cout << "==分割线==" << endl;
char arr[3] = {'a', 'b', 'c'};
cout << &arr[0] << endl;
return 0;
}
按照我的理解来说,输出p1应该是输出str的首地址才对,但是cout直接输出了str。然后输出*p大概还是符合预期的,只有一个a。所以cout不用指定输出的类型,如果你给它一个地址,它大概会输到底的意思?好像有点模糊的体会,不是很懂。
那我的判断条件
argv[1] == "-a",大概是比较第一参数的地址和"-a"的整型值(就像字符有整型值那样吧),会一样才奇怪。于是去百度了比较字符串的函数,有挺多乱七八糟的,考不考虑大小写啊啥的,感觉
strcmp(const char*, const char*)就可以,形参大概是那么个意思,相等就返回零,然后要#include<string.h>。
大概改完了玩坏的代码第一步,然后是计算的问题。。。
代码相关:
大概是知道代码错在哪里了,遍历队列的条件不能写
i < qs.size(),因为每次都会弹出队列元素,所以qs.size()一直都在变的,这样没办法遍历整个队列。怎么说,还好没有找很久。。。还有一件事是,全局变量不能在.h文件里声明,不然每include一次都会再定义一次,会报错说重复定义。
然后这次的代码改动主要是main函数改为从命令行传参,Print类里的输出用了函数重载,Scan类里面的拆分区分了负号和减号以及加了个Calculation类。代码挺长,不具体贴,这里给出链接:点我啊有些注释在dev c++ 里面明明是对齐好的,传上去就乱来。还有六个字变成了乱码,明明是一样的编码不是,其他注释至少还是汉字。去改了下缩进,git表示文件没有变,那我也没办法,将就先看吧。。。那我还是贴一些好了,还有一些调用样例:
Calculation.h
#ifndef CALCULATION_H
#define CALCULATION_H
#include<iostream>
#include<queue>
#include<stack>
using namespace std;
class Calculation
{
public:
//计算并返回算式的答案
double CalculateStringQueue(queue<string> qs);
//返回当前情况在优先级数组里的位置
char GetPosition(string CharStackTop, string t_str);
//借助优先级数组,用两个栈来计算表达式
void CalculateByStack(char order, string t_str);
};
#endif
Calculation.cpp
/*******************************************************************************
FileName: Calculation.cpp
Author:newmoon
Version :2.0
Date:16/07/25
Description:
定义实现Calculation类中的相关方法
Function List:
double CalculateStringQueue(queue<string> qs) 计算并返回算式的答案
void CalculateByStack(char order, string t_str) 用两个栈来计算表达式
char GetPosition(string CharStackTop, string t_str) 返回优先级数组位置
History:
<author> <time> <version > <desc>
newmoon 16/07/27 2.0 代码规范相关
*******************************************************************************/
#include"Calculation.h"
#include<iostream>
#include<sstream>
#include<queue>
#include<stack>
using namespace std;
int flag; //是否继续计算
double ans; //最终的计算结果
stack<double> NumStack; //储存数字的栈
stack<string> CharStack; //储存运算符的栈
//用于运算优先级判断的数组
//行表示运算符栈顶的运算符
//列表示算式当前遍历到的运算符
//">"表示栈顶优先级高,应弹出来进行计算
//"<"表示栈顶优先级低,遍历到的运算符直接入栈
//"="表示遍历到底,NumStack最后一个元素即答案
//或是遍历到")"且栈顶为"(",应弹出栈顶继续遍历
//"0"表示算式有误
//'+', '-', '*', '/', '(', ')', '#'
char order[7][7] = {{'>', '>', '<', '<', '<', '>', '>'}, //'+'
{'>', '>', '<', '<', '<', '>', '>'}, //'-'
{'>', '>', '>', '>', '<', '>', '>'}, //'*'
{'>', '>', '>', '>', '<', '>', '>'}, //'/'
{'<', '<', '<', '<', '<', '=', '0'}, //'('
{'>', '>', '>', '>', '0', '>', '>'}, //')'
{'<', '<', '<', '<', '<', '0', '='} //'#'
};
/**********************************************
Description:返回优先级数组位置
Input:运算符栈的栈顶元素string CharStackTop
算式当前遍历到的运算符string t_str
Output:无
Return:优先级数组的字符型元素order[x][y];
Others:无
***********************************************/
char Calculation :: GetPosition(string CharStackTop, string t_str)
{
int x, y;
switch (CharStackTop[0])
{
case '+':
x = 0;
break;
case '-':
x = 1;
break;
case '*':
x = 2;
break;
case '/':
x = 3;
break;
case '(':
x = 4;
break;
case ')':
x = 5;
break;
case '#':
x = 6;
break;
}
switch (t_str[0])
{
case '+':
y = 0;
break;
case '-':
y = 1;
break;
case '*':
y = 2;
break;
case '/':
y = 3;
break;
case '(':
y = 4;
break;
case ')':
y = 5;
break;
case '#':
y = 6;
break;
}
return order[x][y];
}
/*****************************************
Description:用两个栈来计算表达式
Input:优先级数组元素char order
算式当前遍历到的运算符string t_str
Output:无
Return:无
Others:答案存在全局变量ans里
******************************************/
void Calculation :: CalculateByStack(char order, string t_str)
{
char m_order; //表示优先级数组中的位置
double num, num1, num2; //用于辅助计算
//借助优先级数组进行具体计算
switch (order)
{
//栈顶的运算符优先级较高
//弹出栈顶的运算符和两个数来计算
case '>':
num1 = NumStack.top();
NumStack.pop();
num2 = NumStack.top();
NumStack.pop();
switch (CharStack.top()[0])
{
case '+':
num = num1 + num2;
NumStack.push(num);
CharStack.pop();
break;
case '-':
num = num2 - num1;
NumStack.push(num);
CharStack.pop();
break;
case '*':
num = num1 * num2;
NumStack.push(num);
CharStack.pop();
break;
case '/':
num = num2 / num1;
NumStack.push(num);
CharStack.pop();
break;
}
//下一个栈顶元素优先级仍然较高则继续计算
while(!CharStack.empty() && flag)
{
m_order = GetPosition(CharStack.top(), t_str);
CalculateByStack(m_order, t_str);
}
break;
//栈顶运算符优先级较低
//遍历到运算符直接入栈
case '<':
flag = 0;
CharStack.push(t_str);
break;
case '=':
//表示遍历结束
if (t_str[0] == '#')
{
//最终答案
ans = NumStack.top();
NumStack.pop();
CharStack.pop();
}
//遍历到")"且栈顶为"(",应弹出栈顶继续遍历
else
{
CharStack.pop();
flag = 0;
}
break;
//算式有误的"0"情况
default:
cout << "输入的算式有误" << endl;
exit(1);
}
}
/*******************************************
Description:计算并返回算式的答案
Input:拆分好好的算式队列queue<string> qs
Output:无
Return:算式的答案
Others:无
********************************************/
double Calculation :: CalculateStringQueue(queue<string> qs)
{
//辅助判断遍历结束
qs.push("#");
CharStack.push("#");
char m_order; //表示优先级数组中的位置
string t_str; //遍历到的队列元素
double t_num; //辅助将string转为double
int n = qs.size(); //每次循环qs.size()都会减小
stringstream stream; //辅助将string转为double
//遍历队列开始计算
for (int i = 0; i < n; i++)
{
flag = 1; //是否继续计算
t_str = qs.front();
qs.pop();
//遍历到运算符,进行相应计算
if (t_str == "+" || t_str == "-" || t_str == "*"
|| t_str == "/" || t_str == "("
|| t_str == ")" || t_str == "#")
{
//借助优先级数组判断运算的优先级
m_order = GetPosition(CharStack.top(), t_str);
//实际的计算
CalculateByStack(m_order, t_str);
}
//遍历到数字,转为double并入栈
else
{
stream.clear();
stream << t_str;
stream >> t_num;
NumStack.push(t_num);
}
}
return ans;
}
调用样例:
c++计算器后续(3)的更多相关文章
- 使用HTML+CSS,jQuery编写的简易计算器后续(添加了键盘监听)
之前发布了一款简易的计算器,今天做了一下修改,添加了键盘监听事件,不用再用鼠标点点点啦 JS代码: var yunSuan = 0;// 运算符号,0-无运算;1-加法;2-减法;3-乘法;4-除法 ...
- c++计算器后续(5)
自娱自乐: 大概是重新开始玩qt,然后MFC和第四步附加的作业大概不会去玩了.以上. QT相关: 阶段一: 原来作业里举了qt和mfc这两个做界面的东西,网上都说qt容易上手,学了mfc再来看qt简直 ...
- c++计算器后续(4)
自娱自乐: 大概是终于做到没做完的部分了,第三步助教学长的评论还没去改,感觉那个把读取文件放到Scan里面比较麻烦,其他大概还好.以上. 文件读写: 先是原来的残留问题,都是和fstream :: o ...
- c++计算器后续(2)
自娱自乐: 大概是了解了一下前缀.中缀.后缀表示法是啥,并没有去深究,比如考虑实现啊,然后Calculation类里面的计算方法还是选用原来的直接对中缀表达式求值,只是把代码改得规范点,以上. 各表示 ...
- c++计算器后续(1)
自娱自乐: 大概是一直在说的代码规范,大概是玩一玩,以上. 代码规范: 参考原文:链接 相关节选: 4 程序的版式 4.4规则:较长的语句(>80字符)要分成多行书写. 4.5规则:不允许把多个 ...
- 微信小程序计算器后后续
改的眼睛都要瞎了,总算是知道问题出哪了 最后一段 在等号里面计算输入的数组,这个判断的主要操作是将输入的数据的数组进行数和符号的拆分然后再计算,把数按字符串输入数组,然后将数和符号进行拆分 ,最后通过 ...
- 微信小程序计算器模拟后续
今天按着自己的思路又重打了一遍 wxml没什么说的,就是分块起名,显示数字和结果的作为屏幕,数字键盘一行四块 <view class="onTop"> <view ...
- 【IOS开发笔记03-视图相关】简单计算器的实现
UIView 经过前几天的快速学习,我们初步了解的IOS开发的一些知识,中间因为拉的太急,忽略了很多基础知识点,这些知识点单独拿出来学习太过枯燥,我们在今后的项目中再逐步补齐,今天我们来学习APP视图 ...
- Js函数初学者练习(一)switch-case结构实现计算器。
前 言 JRedu 给大家介绍一点JS函数的练习题希望初学者多做一些练习能够更好的掌握JS的函数,以及能够提升大家的逻辑思维.(我也是个渣渣希望路过的大神多提建议或意见) 希望能够对大家有所帮助 ...
随机推荐
- <数据挖掘导论>读书笔记11异常检测
异常检测的目标是发现与大部分其他对象不同的对象.通常,异常对象被称作离群点(Outlier). 异常检测也称偏差检测(Deviation detection),因为异常对象的属性值明显偏离期望的或者常 ...
- 推荐网站 explainshell.com
ls 显示指定目录下的文件和目录,默认为当前目录. -a 显示所有文件及目录 (ls内定将文件名或目录名称开头为"."的视为隐藏档,不会列出) -l 除文件名称外,亦将文件型态.权 ...
- SSIS教程:创建简单的ETL包 -- 5. 添加包部署模型的包配置(Adding Package Configurations for the Package Deployment Model)
包配置允许您从开发环境的外部设置运行时属性和变量. 配置允许您开发灵活且易于部署和分发的包.Microsoft Integration Services 提供了以下配置类型: XML 配置文件 环境变 ...
- Bundle传递数据,Handler更新UI
Bundle主要用于传递数据:它保存的数据,是以key-value(键值对)的形式存在的. Bundle经常使用在Activity之间或者线程间传递数据,传递的数据可以是boolean.byte.in ...
- android recycleView 简单使用二---分割线
转自:https://www.jianshu.com/p/b46a4ff7c10a RecyclerView没有像之前ListView提供divider属性,而是提供了方法 recyclerView. ...
- GIT 基础-基础命令
环境 centos7 1.安装 #yum install git 2.创建本地仓库 ( 这里用 /www/git) 这里里有个隐藏的文件夹 ```.git``` 为git仓库的配置文件夹, 不可随意修 ...
- 进度监视器--ProgressMonitorInputStream
进度监视器--ProgressMonitorInputStream ProgressMonitorInputStream 可以创建一个进度监视器,以监视读取输入流的进度.如果需要一段时间,将会弹出 P ...
- linux ssh免密登陆
大致流程: 两台linux系统A B 如果A要登陆到B 1.生成A的密钥对 2.将A的公钥拷贝到B的authorized_keys中即可 可以使用命令:ssh-copy-id -i ~/.ssh/id ...
- 通用CSS命名规范
一.文件命名规范 样式文件命名主要的 master.css布局,版面 layout.css专栏 columns.css文字 font.css打印样式 print.css主题 themes.css [/ ...
- C#与.NET的区别和C#程序结构
C#语言及其特点 (1)语法简洁,不允许直接操作做内存,去掉指针操作 (2)彻底的面向对象设计,C#具有面向对象所应用的一切特性:封装.继承.多态 (3)与Web紧密结合,C#支持绝大多数的Web标准 ...


