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的函数,以及能够提升大家的逻辑思维.(我也是个渣渣希望路过的大神多提建议或意见) 希望能够对大家有所帮助 ...
随机推荐
- Hudson-ci/Using Hudson/Installing Hudson/Installing Hudson RPM--官方文档
< Hudson-ci | Using Hudson | Installing Hudson(Redirected from Hudson-ci/Installing Hudson RPM) ...
- 决策树遇到sklearn.exceptions.NotFittedError: XXX instance is not fitted yet. Call 'fit' with appropriate arguments before using this method.的解决方案
1.异常信息: C:\Python36\python36.exe "E:/python_project/ImoocDataAnalysisMiningModeling/第6章 挖掘建模/6- ...
- 多功能电子通讯录(涉及到了双向链表的使用,Linux文件编程等等)
readme.txt //作为一个程序员,我们咋么能不写用户手册呢!MSP的我觉得用户体验是王道,苹果手机的用户体验的确不错!不过WP加油!我去,扯远了!赶紧看我的程序吧! 歡迎使用多功能電子通訊錄 ...
- Linux笔记-Makefile伪指令解析
本文是我在博客里面找到的,觉得对makefile的伪指令介绍得非常详细了!也提到了伪指令为何要用.PHONY:来声明!希望我的这篇转过来的文章能够帮助大家理解makefile的伪指令! 我的理解: 拿 ...
- 汇编语言、与C语言、实现--汉诺塔--
题意描述: 用汇编语言实现汉诺塔.只需要显示移盘次序,不必显示所移盘的大小,例如: X>Z,X>Y,Z>Y,X>Z,..... (n阶Hanoi塔问题)假设有三个分别命名为 ...
- 航空公司客户价值分析(KMeans聚类)
PS.图片可能不清楚,代码 数据集都在 https://github.com/xubin97/Data-Mining_exp1 项目介绍: 本案例的目标是客户价值识别,通过航空公司客户数据识别不同价值 ...
- var、let、const的区别,以及作用范围。
在es5中一般经常使用的变量有两个级别,一个是用var声明的全局级别的变量,另外一个是函数级别是用var生命在函数内的.本文中将详细讲解我对es6中的const和let的区别. let的使用以及作用范 ...
- Java学习--java中的集合框架、Collection接口、list接口
与数组相比:1.数组的长度固定,而集合的长度可变2.数组只能通过下表访问元素,类型固定,而有的集合可以通过任意类型查找所映射的具体对象 java集合框架:collection(list序列,queue ...
- 经典的SQL面试题及答案
- Web安全相关(四):过多发布(Over Posting)
简介 过多发布的内容相对比较简单,因此,我只打算把原文中的一些关键信息翻译一下.原文链接如下: http://www.asp.net/mvc/overview/getting-started/gett ...