Question

Im creating an infix problem solver and it crashes in the final while loop to finish the last part a of the equations.

I call a final while loop in main to solve whats left on the stack and it hangs there and if i pop the last element from the stack it will leave the loop and return the wrong answer.

//
//
//
//
//
#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;
}
Was it helpful?

Solution

I see a number of things which all likely contribute to the issue of it not working:

  • There are no error or bounds checking. I realize that this is homework and as such may have specific requirements/specifications which eliminate the need for some checks, but you still need some to ensure you are correctly parsing the input. What if you exceed the array size of equ/tmp/t? What if your stack is empty when you try to pop/top it?
  • There are a few if statements that look like else if (t == '+' || '-') which most likely doesn't do what you want them to. This expression is actually always true since '-' is non-zero and is converted to a true value. You probably want else if (t == '+' || t == '-').
  • As far as I can tell you seem to skip parsing or adding '(' to the stack which should make it impossible for you to actually evaluate the expression properly.
  • You have a while loop in the middle of postfix() which skips multiple ')' but doesn't do anything.
  • Your code is very hard to follow. Properly naming variables and functions and eliminating most of the globals (you don't actually need most of them) would help a great deal as would proper indentation and add a few spaces in expressions.
  • There are other minor issues not particularily worth mentioning. For example the covchar() and covnum() functions are much more complex than needed.

I've written a few postfix parsers over the years and I can't really follow what you are trying to do, which isn't to say the way you're trying is impossible but I would suggest re-examining at the base logic needed to parse the expression, particularly nested levels of brackets.

OTHER TIPS

Hope this isn't too harsh but it appears like the code is riddled with various problems. I'm not going to attempt to address all of them but, for starters, your immediate crashes deal with accessing aggregates out of bounds.

Example:

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

k is an instance of std::string. std::string isn't null-terminated. It keeps track of the string's length, so you should be do something like this instead:

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

Those are the more simple kind of errors, but I also see some errors in the overall logic. For example, your tokenizer (postfix function) does not handle the case where the last part of the expression is an operand. I'm not sure if that's an allowed condition, but it's something an infix solver should handle (and I recommend renaming this function to something like tokenize as it's really confusing to have a function called 'postfix' for an infix solver).

Most of all, my advice to you is to make some general changes to your approach.

  1. Learn the debugger. Can't stress this enough. You should be testing your code as you're writing it and using the debugger to trace through it and make sure that state variables are correctly set.

  2. Don't use any global variables to solve this problem. It might be tempting to avoid passing things around everywhere, but you're going to make it harder to do #1 and you're also limiting the generality of your solution. That small time you saved by not passing variables is easily going to cost you much more time if you get things wrong. You can also look into making a class which stores some of these things as member variables which you can avoid passing in the class methods, but especially for temporary states like 'equ' which you don't even need after you tokenize it, just pass it into the necessary tokenize function and do away with it.

  3. initialize your variables as soon as you can (ideally when they are first defined). I see a lot of obsolete C-style practices where you're declaring all your variables at the top of a scope. Try to limit the scope in which you use variables, and that'll make your code safer and easier to get correct. It ties in with avoiding globals (#2).

  4. Prefer alternatives to macros when you can, and when you can't, use BIG_UGLY_NAMES for them to distinguish them from everything else. Using #define to create a preprocessor definition for 'size' actually prevents the code above using the string's 'size' method from working. That can and should be a simple integral constant or, better yet, you can simply use std::string for 'equ' (aside from making it not a file scope global).

  5. Prefer standard C++ library headers when you can. <ctype.h> should be <cctype>, <stdlib.h> should be <cstdlib>, and <stdio.h> should be <stdio>. Mixing non-standard headers with .h extension and standard headers in the same compilation unit can cause problems in some compilers and you'll also miss out on some important things like namespace scoping and function overloading.

Finally, take your time with the solution and put some care and love into it. I realize that it's homework and you're under a deadline, but you'll be facing even tougher deadlines in the real world where this kind of coding just won't be acceptable. Name your identifiers properly, format your code legibly, document what your functions do (not just how each line of code works which is something you actually shouldn't be doing so much later as you understand the language better). Some coding TLC will take you a long way. Really think about how to design solutions to a problem (if we're taking a procedural approach, decompose the problem into procedures as general units of work and not a mere chopped up version of your overall logic). #2 will help with this.

** Example: rather than a function named 'postfix' which works with some global input string and manipulates some global stack and partially evaluates the expression, make it accept an input string and return* the individual tokens. Now it's a general function you can reuse anywhere and you also reduced it to a much easier problem to solve and test. Document it and name it that way as well, focusing on the usage and what it accepts and returns. For instance:

// Tokenize an input string. Returns the individual tokens as
// a collection of strings.
std::vector<std::string> tokenize(const std::string& input);

This is purely an example and it may or may not be the best one for this particular problem, but if you take a proper approach to designing procedures, the end result is that you should have built yourself a library of well-tested, reusable code that you can use again and again to make all your future projects that much easier. You'll also make it easier to decompose complex problems into a number of simpler problems to solve which will make everything easier and the whole coding and testing process much smoother.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top