简体   繁体   English

为什么使用堆栈作为ADT崩溃将中缀转换为后缀表示法?

[英]Why does this conversion of infix to postfix notation using stack as an ADT crash?

#include<iostream>
#include<cstring>
using namespace std;
#define MAX 5
struct node
{
    char data;
    struct node *next;
};
class stack
{
    public:
        node *top;
        stack()         //constructor
        {
            top=NULL;
        }
        char Top()     //return top element without popping
        {
            return(top->data);
        }
        int empty()     //check empty
        {
            if(top==NULL)
                return(1);
            return(0);
        }
        void push(char x)     //push function
        {
            node *p;
            p=new node;
            p->data=x;
            p->next=top;
            top=p;
        }
        char pop()         //pop function
        {
            node *p;
            char x;
            p=top;
            top=top->next;
            x=p->data;
            delete(p);
            return(x);
        }
        int precedence(char x)   //check precedence of operators
        {
            if(x=='(')
                return 0;
            else if(x=='+'||x=='-')
                return 1;
            else if(x=='*'||x=='/'||x=='%')
                return 2;
            return 3;
        }
        void infix_to_postfix(char infix[],char postfix[]);
};
void infix_to_postfix(char infix[],char postfix[])
{
    stack s;
    char x,token;
    int i,j=0;
    for(i=0;infix[i]!='\0';i++)
    {
        token=infix[i];
        if(isalnum(token))
            postfix[j++]=token;
        else
            if(token=='(')
                s.push(token);
            else
                if(token==')')
                {
                    while((x=s.pop())!='(')
                        postfix[j++]=x;
                }

                else
                {
                    while(s.precedence(token)<=s.precedence(s.Top())&& !s.empty())
                        postfix[j++]=s.pop();
                    s.push(token);
                }
    }
    while(!s.empty())
    {
        x=s.pop();
        postfix[j++]=x;
    }
    postfix[j++]='\0';
}
int main()
{
    char infix[30],postfix[30];
    cout<<"\nEnter the infix expression::\n";
    cin>>infix;
    infix_to_postfix(infix,postfix);
    cout<<"/nThe equivalent postfix expression is::"<<postfix;
    return 0;
}

The above code is giving segmentation fault with gedit in Ubuntu...whereas when the same code when run with turbo C in Windows with the required changes as follows...runs correctly... 上面的代码在Ubuntu中使用gedit给出了分段错误...而当在Windows中使用turbo C运行相同的代码时,所需的更改如下...正确运行...

#include<stdio.h>
#include<conio.h>
#include<iostream.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#define MAX 5
struct node
{
    char data;
    struct node *next;
};
class stack
{
    public:
        node *top;
        stack()         //constructor
        {
            top=NULL;
        }
        char Top()     //return top element without popping
        {
            return(top->data);
        }
        int empty()     //check empty
        {
            if(top==NULL)
                return(1);
            return(0);
        }
        void push(char x)     //push function
        {
            node *p;
            p=new node;
            p->data=x;
            p->next=top;
            top=p;
        }
        char pop()         //pop function
        {
            node *p;
            char x;
            p=top;
            top=top->next;
            x=p->data;
            delete(p);
            return(x);
        }
        int precedence(char x)   //check precedence of operators
        {
            if(x=='(')
                return 0;
            else if(x=='+'||x=='-')
                return 1;
            else if(x=='*'||x=='/'||x=='%')
                return 2;
            return 3;
        }
        void infix_to_postfix(char infix[],char postfix[]);
};
void infix_to_postfix(char infix[],char postfix[])
{
    stack s;
    char x,token;
    int i,j=0;
    for(i=0;infix[i]!='\0';i++)
    {
        token=infix[i];
        if(isalnum(token))
            postfix[j++]=token;
        else
            if(token=='(')
                s.push(token);
            else
                if(token==')')
                {
                    while((x=s.pop())!='(')
                        postfix[j++]=x;
                }

                else
                {
                    while(s.precedence(token)<=s.precedence(s.Top())&& !s.empty())
                        postfix[j++]=s.pop();
                    s.push(token);
                }
    }
    while(!s.empty())
    {
        x=s.pop();
        postfix[j++]=x;
    }
    postfix[j++]='\0';
}
int main()
{
    char infix[30],postfix[30];
    cout<<"\nEnter the infix expression::\n";
    cin>>infix;
    infix_to_postfix(infix,postfix);
    cout<<"\nEquivalent postfix expression is::"<<postfix;
    getch();
return 0;
}

Why is the problem arising in Ubuntu??? 为什么Ubuntu出现问题???

You never check whether your input stack is empty before directly dereferencing top->data . 在直接取消引用top->data之前top->data您永远不会检查输入堆栈是否为空。 Specifically, this loop: 具体来说,这个循环:

  while(s.precedence(token)<=s.precedence(s.Top())&& !s.empty())
        postfix[j++]=s.pop();
  s.push(token);

can, and in your case will , dereference an empty stack because you check the empty state after you've already dereferenced the top pointer via s.Top() . 可以,并且在您的情况下, 取消引用空堆栈,因为通过s.Top()取消引用顶部指针检查空状态。 You can avoid the inappropriate dereference by using boolean short-circuiting and the proper evaluation order: 您可以通过使用布尔短路和正确的评估顺序来避免不适当的取消引用:

  while(!s.empty() && s.precedence(token)<=s.precedence(s.Top()))
        postfix[j++]=s.pop();
  s.push(token);

Input 输入

A*(B+C/(D-A))

Output 产量

The equivalent postfix expression is:: ABCDA-/+* 等效的后缀表达式是:: ABCDA-/+*

That said, this is extremely brittle. 也就是说,这非常脆弱。 Unless specifically instructed to do so there is no reason you shouldn't be using a custom stack in the first place, as the standard adapter std::stack<> will remove about 90% of this code, and I strongly suggest taking advantage of that. 除非特别指示这样做,否则你没有理由不首先使用自定义堆栈,因为标准适配器std::stack<>将删除大约90%的代码,我强烈建议利用那。

Finally, this is flat-out bug. 最后,这是一个彻头彻尾的错误。 Windows or Ubuntu makes no difference. Windows或Ubuntu没有区别。 It invokes undefined behavior. 它调用未定义的行为。 That it didn't crash on Windows means you were lucky (or not, since you assumed it was ok because it didn't crash); 它没有在Windows上崩溃意味着你很幸运(或者没有,因为你认为它没问题,因为它没有崩溃); not right. 不对。 And in case you're wondering how I noticed this, I saw it in the code, but confirmed it with Valgrind, which confirmed my suspicion immediately . 如果你想知道我是怎么注意到的,我在代码中看到了它,但是用Valgrind证实了这一点,这立即证实了我的怀疑。


Using Standard Library for the Heavy Lifting 使用标准库进行重型提升

This gets considerably simpler when you use classes from the standard library for most of the operations, as you can hopefully see below. 当您在大多数操作中使用标准库中的类时,这会变得相当简单,您可以在下面看到。 I kept your algorithm intact, but just used the std::stack adapter and std::string classes for the guts: 我保持你的算法完整,但只是使用std::stack adapter和std::string类的guts:

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

static int precedence(char x)   //check precedence of operators
{
    if(x=='(')
        return 0;
    else if(x=='+'||x=='-')
        return 1;
    else if(x=='*'||x=='/'||x=='%')
        return 2;
    return 3;
}

std::string infix_to_postfix(const std::string& infix)
{
    std::stack<char> s;
    std::string postfix;

    for (auto ch : infix)
    {
        if (isalnum(ch))
            postfix.push_back(ch);

        else if (ch == '(')
            s.push(ch);

        else if(ch == ')')
        {
            while (!s.empty())
            {
                ch = s.top();
                s.pop();
                if (ch == '(')
                    break;
                postfix.push_back(ch);
            }
        }

        else
        {
            while(!s.empty() && precedence(ch)<=precedence(s.top()))
            {
                postfix.push_back(s.top());
                s.pop();
            }
            s.push(ch);
        }
    }

    while(!s.empty())
    {
        postfix.push_back(s.top());
        s.pop();
    }

    return postfix;
}

int main()
{
    const char infix[] = "A*(B+C/(D-A)+2*(E-F))";
    cout << "\nThe equivalent postfix expression is: " << infix_to_postfix(infix);
    return 0;
}

Input 输入

A*(B+C/(DA)+2*(EF))

Output 产量

The equivalent postfix expression is: ABCDA-/+2EF-*+* 等效的后缀表达式为: ABCDA-/+2EF-*+*

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM