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;
}
调用样例: