我创建了一个中缀问题求解器,它在最后的while循环中崩溃,以完成方程式的最后一部分。
我在main中调用最后一个while循环来解决堆栈上剩下的什么,它会挂起,如果我从堆栈中弹出最后一个元素,它将离开循环并返回错误的答案。
//
//
//
//
//
#include <iostream>
#include<stack>
#include<string>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
using namespace std;
#define size 30
int count=0;
int count2=0;
int total=0;
stack< string > prob;
char equ[size];
char temp[10];
string oper;
string k;
char t[10];
int j=0;
char y;
int solve(int f,int s, char o)
{
cout<<"f="<<f<<endl;
cout<<"s="<<s<<endl;
cout<<"o="<<o<<endl;
int a;
if (o== '*')//checks the operand stack for operator
{
cout << f << "*" << s << endl;
a= f*s;
}
if (o == '/')//checks the operand stack for operator
{
cout << f << "/" << s << endl;
if(s==0)
{
cout<<"Cant divide by 0"<<endl;
}
else
a= f/s;
}
if (o == '+')//checks the operand stack for operator
{
cout << f << "+" << s << endl;
a= f+s;
}
if (o == '-')//checks the operand stack for operator
{
cout << f << "-" << s << endl;
a= f-s;
}
return a;
}
int covnum()
{
int l,c;
k=prob.top();
for(int i=0;k[i]!='\n';i++)t[i]=k[i];
return l=atoi(t);
}
char covchar()
{
k=prob.top();
for(int i=0;k[i]!='\n';i++)t[i]=k[i];
return t[0];
}
void tostring(int a)
{
stringstream out;
out << a;
oper = out.str();
}
void charstack(char op)
{
oper=op;
prob.push(oper);
}
void numstack(char n[])
{
oper=n;
prob.push(oper);
}
void setprob()
{
int f,s;
char o;
char t;
int a;
int i;
t=covchar();
if(ispunct(t))
{
if(t=='(')
{
prob.pop();
}
if(t==')')
{
prob.pop();
}
else if(t=='+'||'-')
{
y=t;
prob.pop();
}
else if(t=='/'||'*')
{
y=t;
prob.pop();
}
}
cout<<"y="<<y<<endl;
i=covnum();
cout<<"i="<<i<<endl;
s=i;
prob.pop();
t=covchar();
cout<<"t="<<t<<endl;
if(ispunct(t))
{
o=t;
prob.pop();
}
i=covnum();
cout<<"i="<<i<<endl;
f=i;
prob.pop();
t=covchar();
if (t=='('||')')
{
prob.pop();
}
a=solve(f,s, o);
tostring(a);
prob.push(oper);
cout<<"A="<<prob.top()<<endl;
}
void postfix()
{
int a=0;
char k;
for(int i=0;equ[i]!='\0';i++)
{
if(isdigit(equ[i]))//checks array for number
{
temp[count]=equ[i];
count++;
}
if(ispunct(equ[i]))//checks array for operator
{
if(count>0)//if the int input is done convert it to a string and push to stack
{
numstack(temp);
count=0;//resets the counter
}
if(equ[i]==')')//if char equals the ')' then set up and solve that bracket
{
setprob();
i++;//pushes i to the next thing in the array
total++;
}
while(equ[i]==')')//if char equals the ')' then set up and solve that bracket
{
i++;
}
if(isdigit(equ[i]))//checks array for number
{
temp[count]=equ[i];
count++;
}
if(ispunct(equ[i]))
{
if(equ[i]==')')//if char equals the ')' then set up and solve that bracket
{
i++;
}
charstack(equ[i]);
}
if(isdigit(equ[i]))//checks array for number
{
temp[count]=equ[i];
count++;
}
}
}
}
int main()
{
int a=0;
char o;
int c=0;
cout<<"Enter Equation: ";
cin>>equ;
postfix();
while(!prob.empty())
{
setprob();
a=covnum();
cout<<a<<" <=="<<endl;
prob.pop();
cout<<prob.top()<<"<top before c"<<endl;
c=covnum();
a=solve(c,a,y);
}
cout<<"Final Awnser"<<a<<endl;
system ("PAUSE");
return 0;
}
答案 0 :(得分:3)
希望这不是太苛刻但似乎代码充满了各种各样的问题。我不打算尝试解决所有这些问题,但是对于初学者来说,你的直接崩溃会导致访问聚合超出范围。
示例:
for(int i=0;k[i]!='\n';i++)
k是std :: string的一个实例。 std :: string不是以null结尾的。它跟踪字符串的长度,所以你应该做这样的事情:
for(int i=0;i<k.size();i++)
这些是更简单的错误,但我也看到整体逻辑中的一些错误。例如,您的tokenizer(后缀函数)不处理表达式的最后部分是操作数的情况。我不确定这是否是一个允许的条件,但它是一个中缀解算器应该处理的东西(我建议将此函数重命名为tokenize,因为对于一个中缀解算器来说有一个名为'postfix'的函数真的很混乱)。
最重要的是,我给你的建议是对你的方法做一些一般的改变。
了解调试器。不能强调这一点。您应该在编写代码时测试代码,并使用调试器跟踪代码并确保正确设置状态变量。
不要使用任何全局变量来解决此问题。避免在任何地方传递东西可能很诱人,但是你会更难做到#1并且你也限制了解决方案的一般性。如果你弄错了,你通过不传递变量节省的那么短的时间很容易花费你更多的时间。您还可以考虑创建一个类,它将某些内容存储为成员变量,您可以避免传递给类方法,但特别是对于像'equ'这样的临时状态,在您将其标记化后甚至不需要它,只需传递它进入必要的tokenize函数并取消它。
尽快初始化变量(理想情况下,首次定义变量时)。我看到很多过时的C风格实践,你在范围顶部声明所有变量。尝试限制使用变量的范围,这将使您的代码更安全,更容易正确。它与避免全局变量联系在一起(#2)。
尽可能选择宏的替代品,当您不能使用时,请使用BIG_UGLY_NAMES将它们与其他所有内容区分开来。使用#define为'size'创建预处理器定义实际上会阻止上面的代码使用字符串的'size'方法工作。这可以而且应该是一个简单的整数常量,或者更好的是,你可以简单地使用std :: string作为'equ'(除了使它不是一个全局的文件范围)。
尽可能选择标准C ++库标题。 <ctype.h>
应为<cctype>
,<stdlib.h>
应为<cstdlib>
,<stdio.h>
应为<stdio>
。在同一编译单元中将非标准头与.h扩展名和标准头混合在一起可能会导致某些编译器出现问题,并且您也会错过命名空间作用域和函数重载等重要内容。
最后,花点时间使用解决方案并对其进行一些关心和爱护。我意识到这是家庭作业,你处于截止日期之前,但在现实世界中你将面临更艰难的最后期限,在这种情况下,这种编码是不可接受的。正确命名您的标识符,清晰地格式化您的代码,记录您的函数所做的事情(不仅仅是每行代码如何工作,这是您在以后更好地理解语言时实际上不应该做的事情)。一些编码TLC将带您走很长的路。真的想一想如何设计解决问题的方法(如果我们采用程序方法,将问题分解为程序作为一般工作单元,而不仅仅是整个逻辑的简化版本)。 #2将有助于此。
**示例:而不是名为'postfix'的函数,它与某些全局输入字符串一起使用并操纵某些全局堆栈并部分计算表达式,使其接受输入字符串并返回*各个标记。现在它是一个可以在任何地方重复使用的通用功能,您还可以将其简化为更容易解决和测试的问题。记录它并以这种方式命名,重点关注用法以及它接受和返回的内容。例如:
// Tokenize an input string. Returns the individual tokens as
// a collection of strings.
std::vector<std::string> tokenize(const std::string& input);
这纯粹是一个例子,对于这个特定的问题,它可能是也可能不是最好的例子,但是如果你采用适当的方法设计程序,最终的结果是你应该自己构建一个经过良好测试的库,可重复使用的代码,您可以反复使用,以使您未来的所有项目更容易。您还可以更轻松地将复杂问题分解为许多更简单的问题来解决,这将使一切变得更容易,整个编码和测试过程更加顺畅。
答案 1 :(得分:2)
我看到很多事情都可能导致它无效的问题:
else if (t == '+' || '-')
的if语句很可能不符合您的要求。该表达式实际上始终为真,因为' - '非零并且转换为真值。您可能需要else if (t == '+' || t == '-')
。postfix()
中间有一个while循环,跳过多个')',但没有做任何事情。