2

我创建了一个中缀问题求解器,它在最后的 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;
}
4

2 回答 2

3

希望这不是太苛刻,但看起来代码充满了各种问题。我不会尝试解决所有这些问题,但是,对于初学者来说,您的直接崩溃处理的是访问越界的聚合。

例子:

for(int i=0;k[i]!='\n';i++)

k 是 std::string 的一个实例。std::string 不是以空值结尾的。它跟踪字符串的长度,所以你应该这样做:

for(int i=0;i<k.size();i++)

这些是更简单的错误,但我在整体逻辑中也看到了一些错误。例如,您的分词器(后缀函数)不处理表达式的最后一部分是操作数的情况。我不确定这是否是允许的条件,但这是中缀求解器应该处理的事情(我建议将此函数重命名为类似 tokenize 的东西,因为为中缀求解器提供一个名为“后缀”的函数真的很令人困惑)。

最重要的是,我对你的建议是对你的方法进行一些一般性的改变。

  1. 学习调试器。不能强调这一点。您应该在编写代码时对其进行测试,并使用调试器对其进行跟踪,并确保正确设置了状态变量。

  2. 不要使用任何全局变量来解决这个问题。避免在任何地方传递东西可能很诱人,但你会让#1 变得更难,而且你也限制了解决方案的通用性。如果你弄错了,你通过不传递变量节省的时间很容易花费你更多的时间。您还可以考虑创建一个将其中一些内容存储为成员变量的类,您可以避免在类方法中传递它,但特别是对于像“equ”这样的临时状态,您在标记它之后甚至不需要它,只需传递将其放入必要的标记化功能并取消它。

  3. 尽快初始化变量(最好是在首次定义变量时)。我看到很多过时的 C 风格实践,你在作用域的顶部声明所有变量。尝试限制使用变量的范围,这将使您的代码更安全,更容易正确。它与避免全局变量(#2)有关。

  4. 如果可以,请优先使用宏的替代品,如果不能,请使用 BIG_UGLY_NAMES 将它们与其他所有内容区分开来。使用#define 为“size”创建预处理器定义实际上阻止了上面使用字符串的“size”方法的代码工作。这可以而且应该是一个简单的整数常量,或者更好的是,您可以简单地将 std::string 用于“equ”(除了使其不是全局文件范围之外)。

  5. 尽可能首选标准 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);

这纯粹是一个示例,它可能是也可能不是这个特定问题的最佳示例,但是如果您采用正确的方法来设计程序,最终结果是您应该为自己构建了一个经过良好测试、可重用的代码库您可以一次又一次地使用它来使您未来的所有项目变得更加容易。您还将更容易将复杂的问题分解为许多更简单的问题来解决,这将使一切变得更容易,并且整个编码和测试过程更加顺畅。

于 2012-02-26T23:46:49.003 回答
2

我看到了许多可能导致它无法正常工作的问题:

  • 没有错误或边界检查。我意识到这是家庭作业,因此可能有特定的要求/规范,无需进行一些检查,但您仍然需要一些来确保您正确解析输入。如果超过 equ/tmp/t 的数组大小怎么办?如果当您尝试弹出/置顶时您的堆栈为空怎么办?
  • 有一些 if 语句看起来else if (t == '+' || '-')很可能不符合您的要求。这个表达式实际上总是正确的,因为 '-' 是非零的并且被转换为一个真值。你可能想要else if (t == '+' || t == '-').
  • 据我所知,您似乎跳过了解析或将“(”添加到堆栈中,这应该使您无法正确地实际评估表达式。
  • 您在中间有一个 while 循环,postfix()它会跳过多个 ')' 但不执行任何操作。
  • 您的代码很难遵循。正确命名变量和函数并消除大多数全局变量(您实际上并不需要它们中的大多数)将有很大帮助,就像正确缩进并在表达式中添加一些空格一样。
  • 还有其他一些小问题并不特别值得一提。例如 covchar() 和 covnum() 函数比需要的复杂得多。

多年来,我编写了一些后缀解析器,但我无法真正遵循您正在尝试做的事情,这并不是说您尝试的方式是不可能的,但我建议重新检查基本逻辑需要解析表达式,尤其是括号的嵌套级别。

于 2012-02-26T23:48:03.627 回答