使用堆栈评估后缀表达式时出现分段错误

时间:2016-03-23 06:15:46

标签: c++ stack

这是完整实现的中缀到后缀转换和后期表达式的评估。 "中缀到后缀转换"是成功的,但评估"给出一个段错误。

代码是:

#include<iostream>
//#include<stack>
#include<string>
#include<cmath>

using namespace std;

template<class T1>
struct node
{

    T1 data;
    node<T1> *next;

};
template<class T1>
class stack
{
    node<T1> *head;
    public:
         stack()
        {
            head=NULL;
        }
        void push(T1);
        int empty()
            {
                if(head==NULL)
                return 1;
                return 0;
            }
        T1 top()
            {
                T1 temp;
                temp=head->data;
                return (temp);
            }
        T1 pop();
        void show();

};
template<class T1>
void stack<T1>::push(T1 input)
{
    node<T1> *ptr;
    ptr=new node<T1>;
    ptr->data=input;
    ptr->next=NULL;
    if(head!=NULL)
    {
        ptr->next=head;
    }
    head=ptr;
}
template<class T1>
T1 stack<T1>::pop()
{
    node<T1> *temp;
    T1 output;
    temp=head;
    output=temp->data;
    head=head->next;
    delete temp;
    return output;

}
template<class T1>
void stack<T1>::show()
{
        node<T1> *temp;
    temp=head;
    while(temp!=NULL)
    {
        cout<<temp->data;
        temp=temp->next;    
    }
}

void evaluate(string postfix)
{
  stack<float>s;
  float a;
  int i;
  for(i=0; i < postfix.length(); i++)
  {
  if(isalpha(postfix[i]))
    {
    cout<<"enter the value of\t";
    cout<<postfix[i];
    cin>>a;
    s.push(a);
    }
    else
    {
      float x,y;
      y=s.pop(); //s.pop();
      x=s.pop(); //s.pop();

      char token=postfix[i];
      if(token=='+')
      {

      x=x+y;
      s.push(x);
      }
      if(token=='-')
      {

      x=x-y;
      s.push(x);
      }
      if(token=='*')
      {

      x=x*y;
      s.push(x);
      }
      if(token=='/')
      {

      x=x/y;
      s.push(x);
      }
      if(token=='^')
      {

      x=pow(x,y);
      s.push(x);
      }

    }
  }
  cout<<"\t Evaluated result is \t";
  cout<<s.top();
  s.pop();
}

// Function to convert Infix expression to postfix
string InfixToPostfix(string expression);

// Function to verify whether an operator has higher precedence over other
int HasHigherPrecedence(char operator1, char operator2);

// Function to verify whether a character is operator symbol or not.
bool IsOperator(char C);

// Function to verify whether a character is alphanumeric chanaracter (letter or numeric digit) or not.
bool IsOperand(char C);

int main()
{
  string expression;
  cout<<"Enter Infix Expression \n";
  getline(cin,expression);
  string postfix = InfixToPostfix(expression);
  cout<<"Postfix is : = "<<postfix<<"\n";
  evaluate(expression);
}

// Function to evaluate Postfix expression and return output
string InfixToPostfix(string expression)
{
  // Declaring a Stack from Standard template library in C++.
  stack<char> S;
  string postfix = ""; // Initialize postfix as empty string.
  for(int i = 0;i< expression.length();i++) {

    // Scanning each character from left.
    // If character is a delimitter, move on.
    if(expression[i] == ' ' || expression[i] == ',') continue;

    // If character is operator, pop two elements from stack, perform operation and push the result back.
    else if(IsOperator(expression[i]))
    {
      while(!S.empty() && S.top() != '(' && HasHigherPrecedence(S.top(),expression[i]))
      {
        postfix+= S.top();
        S.pop();
      }
      S.push(expression[i]);
    }
    // Else if character is an operand
    else if(IsOperand(expression[i]))
    {
      postfix +=expression[i];
    }

    else if (expression[i] == '(')
    {
      S.push(expression[i]);
    }

    else if(expression[i] == ')')
    {
      while(!S.empty() && S.top() !=  '(') {
        postfix += S.top();
        S.pop();
      }
      S.pop();
    }
  }

  while(!S.empty()) {
    postfix += S.top();
    S.pop();
  }

  return postfix;
}

// Function to verify whether a character is english letter or numeric digit.
// We are assuming in this solution that operand will be a single character
bool IsOperand(char C)
{
  if(C >= '0' && C <= '9') return true;
  if(C >= 'a' && C <= 'z') return true;
  if(C >= 'A' && C <= 'Z') return true;
  return false;
}

// Function to verify whether a character is operator symbol or not.
bool IsOperator(char C)
{
  if(C == '+' || C == '-' || C == '*' || C == '/' || C== '^')
    return true;

  return false;
}

// Function to verify whether an operator is right associative or not.
int IsRightAssociative(char op)
{
  if(op == '^') return true;
  return false;
}

// Function to get weight of an operator. An operator with higher weight will have higher precedence.
int GetOperatorWeight(char op)
{
  int weight = -1;
  switch(op)
  {
  case '+':
  case '-':
    weight = 1;
    break;
  case '*':
  case '/':
    weight = 2;
    break;
  case '^':
    weight = 3;
    break;
  }
  return weight;
}

// Function to perform an operation and return output.
int HasHigherPrecedence(char op1, char op2)
{
  int op1Weight = GetOperatorWeight(op1);
  int op2Weight = GetOperatorWeight(op2);

  // If operators have equal precedence, return true if they are left associative.
  // return false, if right associative.
  // if operator is left-associative, left one should be given priority.
  if(op1Weight == op2Weight)
  {
    if(IsRightAssociative(op1)) return false;
    else return true;
  }
  return op1Weight > op2Weight ?  true: false;
}

在调试时我得到:

Enter Infix Expression 
(5^2)+5

Breakpoint 1, main () at stack.cpp:155
warning: Source file is more recent than executable.
155   string postfix = InfixToPostfix(expression);
Missing separate debuginfos, use: dnf debuginfo-install libgcc-5.3.1-2.fc23.x86_64 libstdc++-5.3.1-2.fc23.x86_64
(gdb) n
156   cout<<"Postfix is : = "<<postfix<<"\n";
(gdb) n
Postfix is : = 52^5+
157   evaluate(expression);
(gdb) s
evaluate (postfix="(5^2)+5") at stack.cpp:81
81    stack<float>s;
(gdb) s
stack<float>::stack (this=0x7fffffffddd0) at stack.cpp:23
23              head=NULL;
(gdb) s
24          }
(gdb) s
evaluate (postfix="(5^2)+5") at stack.cpp:84
84    for(i=0; i < postfix.length(); i++)
(gdb) s
86    if(isalpha(postfix[i]))
(gdb) s
96        y=s.pop(); //s.pop();
(gdb) s
stack<float>::pop (this=0x7fffffffddd0) at stack.cpp:60
60      temp=head;
(gdb) s
61      output=temp->data;
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401a05 in stack<float>::pop (this=0x7fffffffddd0) at stack.cpp:61
61      output=temp->data;
(gdb) s
s
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.

问题在于:

 float x,y;
      y=s.pop(); //s.pop();
      x=s.pop(); //s.pop();

of evaluation()函数。

我再次明确地使用了堆栈实现,以便我可以看到问题所在。

在pop函数中,seg。错误来自:output=temp->data;

2 个答案:

答案 0 :(得分:1)

问题出在您的pop方法中。您需要检查head == nullptr。像:

template<class T1>
T1 stack<T1>::pop()
{
    node<T1> *temp;
    T1 output;
    if (head == nullptr)
    {
        // Error handling.... Perhaps:
        throw ....;
    }
    temp=head;
    output=temp->data;
    head=head->next;
    delete temp;
    return output;    
}

如果您的evaluate函数在第一个或第二个循环中采用了错误路径,那么您将取消引用nullptr并获得seg错误。

像这样:

void evaluate(string postfix)
{
    stack<float> s;   // s is empty and head is nullptr
    float a;
    int i;
    for(i=0; i < postfix.length(); i++)
    {
        if(isalpha(postfix[i]))   // Assume this evalutes to false in first loop
        {
            cout<<"enter the value of\t";
            cout<<postfix[i];
            cin>>a;
            s.push(a);
        }
        else
        {
            float x,y;
            y=s.pop();  // then you pop from empty stack and dereference a nullptr

答案 1 :(得分:1)

您的代码中有2个问题:

  • 当您通过expression时,您已将原始evaluate传递给postfix函数:
  • 你永远不会用数字参数填充堆栈!

评估中的循环内容应该是(或多或少):

  if(isalpha(postfix[i]))
    {
    cout<<"enter the value of\t";
    cout<<postfix[i];
    cin>>a;
    s.push(a);
    }
    else if (isdigit(postfix[i])) {   // do not forget to populate stack!
        s.push(0.f + postfix[i] - '0');  // raw conversion of digit to float
    }
    else
      ...

在这个简单的情况下,这足以摆脱seg错误。但是您的算法目前无法处理超过1位的数字......