GCC 和 Visual Studio(CPP、C++)上的不同输出

问题描述 投票:0回答:1

我尝试在 CPP 中编写一个程序,它获取一个中缀表达式,将其转换为后缀表达式,然后使用我执行的堆栈类来计算该表达式。 我认为我写的东西有效,因为我在 Visual Studio 上对其进行了多次测试。但我不知道为什么,测试在 Visual Studio 上有结果 X,在 GCC 上有结果 Y。例如,当我运行程序并在 Visual Studio 上输入 (5+3)*((20/10)+(8-6)) 时,它会打印 32。另一方面,在 GCC 上,它会打印 0。

所以,我的问题是有人知道什么可能导致这种差异吗?也许编译器有什么不同?

我认为这可能是由未定义的行为引起的。但即使确实如此,我也不知道它是在哪里被调用的......

(顺便说一句,在 GCC 中,我没有将 Stack.h 分离到不同的文件,而是将其写在 main 之上 - Visual Studio 上的输出仍然不同)

main.cpp:

#include "Stack.h"
#include <iostream>
#include <string>
#include <cmath>

using namespace std;

bool operatorsPrecedenceCheck(string& str, Stack<char>& stk, const char& ch)
{
    if (ch == '+' || ch == '-')
    {
        Stack<char> help(stk.getSize());
        char stkTop = '\0';
        if (!stk.isEmpty())
            stkTop = stk.top();
        while (!stk.isEmpty() && stkTop != '(')
        {
            stkTop = stk.top();
            if (stk.top() == '*' || stk.top() == '/')
            {
                str += stk.pop();
                str += ' ';
            }
            else
                help.push(stk.pop());
        }
        while (!help.isEmpty())
            stk.push(help.pop());

        stk.push(ch);

        return 1;
    }
    else if (ch == '*' || ch == '/')
    {
        stk.push(ch);

        return 1;
    }


    return 0;

}
bool parenthesisCheck(string& str, Stack<char>& stk, const char& ch)
{
    if (ch == '(')
    {
        stk.push(ch);

        return 1;
    }
    else if (ch == ')')
    {
        while (stk.top() != '(')
        {
            str += stk.pop();
            str += ' ';
        }
        stk.pop();

        return 1;
    }

    return 0;

}

string infixToPostfix(const string& exp)
{
    string str = "";
    Stack<char> stk(exp.length());
    bool actionExecuted = 0;
    for (int i = 0; i < exp.length(); ++i)
    {
        actionExecuted = parenthesisCheck(str, stk, exp[i]);
        if (!actionExecuted)
            actionExecuted = operatorsPrecedenceCheck(str, stk, exp[i]);
        if (!actionExecuted)
        {
            if (exp[i] >= '0' && exp[i] <= '9')
            {
                for (; exp[i] >= '0' && exp[i] <= '9'; ++i)
                    str += exp[i];

                str += ' ';
                --i;
            }
            else
                throw"An illegal value in the expression\n";
        }
    }
    while (!stk.isEmpty())
    {
        str += stk.pop();
        str += ' ';
    }

    str = str.substr(0, str.length() - 1); //Cause of space

    return str;

}

int getValueFromString(const string& str, int& i)
{
    int result = 0;
    int amountOfDigits = 0;
    while (str[i + amountOfDigits] >= '0' && str[i + amountOfDigits] <= '9')
        ++amountOfDigits;

    for (int j = pow(10, amountOfDigits - 1); j >= 1; j /= 10)
        result += (str[i++] - '0') * j;
    --i;

    return result;
}

float calcPostfix(const string& str)
{
    Stack<int>stk(str.length() / 2);
    for (int i = 0; i < str.length(); i += 2)
    {
        if (str[i] >= '0' && str[i] <= '9')
            stk.push(getValueFromString(str, i));
        else if (str[i] == '/')
            stk.push((float)1 / stk.pop() * stk.pop());
        else if (str[i] == '*')
            stk.push(stk.pop() * stk.pop());
        else if (str[i] == '+')
            stk.push(stk.pop() + stk.pop());
        else if (str[i] == '-')
            stk.push(-1 * (stk.pop() - stk.pop()));
        else
            throw"Unknown Operator in Calculating Postfix\\n";
    }

    return stk.top();

}

int main()
{
    try
    {
        string exp;
        cout << "enter an infix expression as a string" << endl;
        cin >> exp;
        string postfix = infixToPostfix(exp);
        cout << postfix << endl;
        cout << calcPostfix(postfix) << endl;
    }
    catch (const char* exc)
    {
        cout << exc;
        exit(-1);
    }
    catch (...)
    {
        cout << "Unknown Error has occured\\n";
        exit(-1);
    }

    return 0;

}

Stack.h:

#ifndef MYSTACK_H
#define MYSTACK_H

template <class T>
class Stack
{
    //Inner class help
    void swap(Stack<T> &a, Stack<T>& b);

    T* data;
    int capacity;
    int size;
public:
    //Constructors & Destructor
    Stack();
    Stack(int capacity_);
    Stack(const Stack<T>& toCopy);
    Stack(Stack<T>&& toMove);
    ~Stack();

    //Methods
    int getCapacity() const;
    int getSize() const;
    void clear();
    bool isEmpty() const;
    bool isFull() const;
    T pop();
    void push(const T& toInsert);
    T top() const;

    //Operators
    Stack<T>& operator= (const Stack<T>& toAssign);
    Stack<T>& operator=(Stack<T>&& toMove);
};

//Inner class help
template<class T>
void Stack<T>::swap(Stack<T>& a, Stack<T>& b)
{
    T* temp_1 = a.data;
    a.data = b.data;
    b.data = temp_1;

    int temp_2 = a.size;
    a.size = b.size;
    b.size = temp_2;

    temp_2 = a.capacity;
    a.capacity = b.capacity;
    b.capacity = temp_2;
}

//Constructors & Destructor
template<class T>
Stack<T>::Stack() : data(nullptr), capacity(0), size(0) {}
template<class T>
Stack<T>::Stack(int capacity_) : capacity(capacity_), size(0) 
{
    data = new T[capacity];
    if (!data)
        throw "ERROR - couldn't allocate memory\n";
}
template<class T>
Stack<T>::Stack(const Stack<T>& toCopy)
{
    size = 0;
    capacity = toCopy.capacity;
    data = new T[capacity];
    if (!data)
        throw "ERROR - couldn't allocate memory\n";

    for (int i = 0; i < toCopy.size; ++i, ++size)
        data[i] = toCopy.data[i];
}
template<class T>
Stack<T>::Stack(Stack<T>&& toMove)
{
    data = nullptr;
    size = capacity = 0;

    swap(*this, toMove);
}
template<class T>
Stack<T>::~Stack()
{
    clear();
}

//Methods
template<class T>
int Stack<T>::getSize() const
{
    return size;
}
template<class T>
int Stack<T>::getCapacity() const
{
    return capacity;
}
template<class T>
void Stack<T>::clear()
{
    if (data)
    {
        delete[] data;
        data = nullptr;
    }
    size = capacity = 0;
}
template <class T>
bool Stack<T>::isEmpty() const
{
    return size == 0;
}
template <class T>
bool Stack<T>::isFull() const
{
    return size == capacity;
}
template <class T>
T Stack<T>::pop()
{
    if (isEmpty())
        throw"Couldn't pop - Stack is empty\n";

    T toReturn = data[--size];
    T* temp = new T[capacity];
    if (!temp)
        throw "ERROR - couldn't allocate memory\n";
    for (int i = 0; i < size; i++)
        temp[i] = data[i];

    delete[]data;
    data = temp;
    
    return toReturn;
}
template <class T>
void Stack<T>::push(const T& toInsert)
{
    if (isFull())
        throw "Couldn't push - stack is full\n";

    T* temp = new T[capacity];
    if (!temp)
        throw "ERROR - couldn't allocate memory\n";
    for (int i = 0; i < size; i++)
        temp[i] = data[i];

    temp[size++] = toInsert;
    delete[]data;
    data = temp;
}
template<class T>
T Stack<T>::top() const
{
    if (isEmpty())
        throw"Couln't return top - Stack is empty\n";

    return data[size - 1];
}

//Operators
template<class T>
Stack<T>& Stack<T>::operator=(const Stack<T>& toAssign)
{
    if (data)
        delete[]data;

    Stack<T>help = toAssign;
    swap(*this,help);
    return *this;
}
template<class T>
Stack<T>& Stack<T>::operator=(Stack<T>&& toMove)
{
    if (data)
        delete[]data;

    data = nullptr;
    size = capacity = 0;
    
    swap(*this, toMove);
    return *this;
}

#endif

GCC 代码

template <class T>
class Stack
{
    //Inner class help
    void swap(Stack<T> &a, Stack<T>& b);

    T* data;
    int capacity;
    int size;
public:
    //Constructors & Destructor
    Stack();
    Stack(int capacity_);
    Stack(const Stack<T>& toCopy);
    Stack(Stack<T>&& toMove);
    ~Stack();

    //Methods
    int getCapacity() const;
    int getSize() const;
    void clear();
    bool isEmpty() const;
    bool isFull() const;
    T pop();
    void push(const T& toInsert);
    T top() const;

    //Operators
    Stack<T>& operator= (const Stack<T>& toAssign);
    Stack<T>& operator=(Stack<T>&& toMove);
};

//Inner class help
template<class T>
void Stack<T>::swap(Stack<T>& a, Stack<T>& b)
{
    T* temp_1 = a.data;
    a.data = b.data;
    b.data = temp_1;

    int temp_2 = a.size;
    a.size = b.size;
    b.size = temp_2;

    temp_2 = a.capacity;
    a.capacity = b.capacity;
    b.capacity = temp_2;
}

//Constructors & Destructor
template<class T>
Stack<T>::Stack() : data(nullptr), capacity(0), size(0) {}
template<class T>
Stack<T>::Stack(int capacity_) : capacity(capacity_), size(0) 
{
    data = new T[capacity];
    if (!data)
        throw "ERROR - couldn't allocate memory\n";
}
template<class T>
Stack<T>::Stack(const Stack<T>& toCopy)
{
    size = 0;
    capacity = toCopy.capacity;
    data = new T[capacity];
    if (!data)
        throw "ERROR - couldn't allocate memory\n";

    for (int i = 0; i < toCopy.size; ++i, ++size)
        data[i] = toCopy.data[i];
}
template<class T>
Stack<T>::Stack(Stack<T>&& toMove)
{
    data = nullptr;
    size = capacity = 0;

    swap(*this, toMove);
}
template<class T>
Stack<T>::~Stack()
{
    clear();
}

//Methods
template<class T>
int Stack<T>::getSize() const
{
    return size;
}
template<class T>
int Stack<T>::getCapacity() const
{
    return capacity;
}
template<class T>
void Stack<T>::clear()
{
    if (data)
    {
        delete[] data;
        data = nullptr;
    }
    size = capacity = 0;
}
template <class T>
bool Stack<T>::isEmpty() const
{
    return size == 0;
}
template <class T>
bool Stack<T>::isFull() const
{
    return size == capacity;
}
template <class T>
T Stack<T>::pop()
{
    if (isEmpty())
        throw"Couldn't pop - Stack is empty\n";

    T toReturn = data[--size];
    T* temp = new T[size];
    if (!temp)
        throw "ERROR - couldn't allocate memory\n";
    for (int i = 0; i < size; i++)
        temp[i] = data[i];

    delete[]data;
    data = temp;
    
    return toReturn;
}
template <class T>
void Stack<T>::push(const T& toInsert)
{
    if (isFull())
        throw "Couldn't push - stack is full\n";

    T* temp = new T[size + 1];
    if (!temp)
        throw "ERROR - couldn't allocate memory\n";
    for (int i = 0; i < size; i++)
        temp[i] = data[i];

    temp[size++] = toInsert;
    delete[]data;
    data = temp;
}
template<class T>
T Stack<T>::top() const
{
    if (isEmpty())
        throw"Couln't return top - Stack is empty\n";

    return data[size - 1];
}

//Operators
template<class T>
Stack<T>& Stack<T>::operator=(const Stack<T>& toAssign)
{
    if (data)
        delete[]data;

    Stack<T>help = toAssign;
    swap(*this,help);
    return *this;
}
template<class T>
Stack<T>& Stack<T>::operator=(Stack<T>&& toMove)
{
    if (data)
        delete[]data;

    data = nullptr;
    size = capacity = 0;
    
    swap(*this, toMove);
    return *this;
}

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

bool operatorsPrecedenceCheck(string& str, Stack<char>& stk, const char& ch)
{
if (ch == '+' || ch == '-')
    {
        Stack<char> help(stk.getSize());
        char stkTop = '\0';
        if (!stk.isEmpty())
            stkTop = stk.top();
        while (!stk.isEmpty() && stkTop!='(') //Not mentioned but required
        {
            stkTop = stk.top();
            if (stk.top() == '*' || stk.top() == '/')
            {
                str += stk.pop();
                str += ' ';
            }
            else
                help.push(stk.pop());
        }
        while (!help.isEmpty())
            stk.push(help.pop());

        stk.push(ch);
        
        return 1;
    }
    else if (ch == '*' || ch == '/')
    {
        stk.push(ch);

        return 1;
    }
    

    return 0;
}
bool parenthesisCheck(string& str, Stack<char>& stk, const char& ch)
{
    if (ch == '(')
    {
        stk.push(ch);

        return 1;
    }
    else if (ch == ')')
    {
        while (stk.top() != '(')
        {
            str += stk.pop();
            str += ' ';
        }
        stk.pop();

        return 1;
    }

    return 0;
}

string infixToPostfix(const string &exp)
{
    string str = "";
    Stack<char> stk(exp.length());
    bool actionExecuted = 0;
    for (int i = 0; i < exp.length(); ++i)
    {
        actionExecuted = parenthesisCheck(str, stk, exp[i]);
        if (!actionExecuted)
            actionExecuted = operatorsPrecedenceCheck(str, stk, exp[i]);
        if (!actionExecuted)
        {
            if (exp[i] >= '0' && exp[i] <= '9')
            {
                for (; exp[i] >= '0' && exp[i] <= '9'; ++i)
                    str += exp[i];

                str += ' ';
                --i;
            }
            else
                throw"An illegal value in the expression\n";
        }
    }
    while (!stk.isEmpty())
    {
        str += stk.pop();
        str += ' ';
    }

    str = str.substr(0,str.length() - 1); //Cause of space

    return str;
}

int getValueFromString(const string& str, int &i)
{
    int result = 0;
    int amountOfDigits = 0;
    while (str[i+amountOfDigits] >= '0' && str[i+amountOfDigits] <= '9')
        ++amountOfDigits;

        for (int j = pow(10,amountOfDigits-1); j>=1; j /= 10)
            result += (str[i++] - '0') * j;
        --i;

    return result;
}

float calcPostfix(const string& str)
{
    Stack<int>stk(str.length()/2);
    for (int i = 0; i < str.length(); i += 2)
    {
        if (str[i] >= '0' && str[i] <= '9')
            stk.push(getValueFromString(str, i));
        else if (str[i] == '/')
            stk.push((float)1 / stk.pop() * stk.pop());
        else if (str[i] == '*')
            stk.push(stk.pop() * stk.pop());
        else if (str[i] == '+')
            stk.push(stk.pop() + stk.pop());
        else if (str[i] == '-')
            stk.push(-1 * (stk.pop() - stk.pop()));
        else
            throw"Unknown Operator in Calculating Postfix\n";
    }

    return stk.top();
}

int main()
{
    try
    {
        string exp;
        cout << "enter an infix expression as a string" << endl;
        cin >> exp;
        string postfix = infixToPostfix(exp);
        cout << postfix << endl;
        cout << calcPostfix(postfix) << endl;
    }
    catch (const char* exc)
    {
        cout << exc;
        exit(-1);
    }
    catch (...)
    {
        cout << "Unknown Error has occured\n";
        exit(-1);
    }

    return 0;
}
c++ visual-studio gcc expression undefined-behavior
1个回答
2
投票

stk.pop() - stk.pop()
中,不能保证左手
pop()
首先发生
,如果更改为:

auto a = stk.pop();
auto b = stk.pop();
stk.push(-1 * (a - b));

您将在不同的编译器中获得相同的行为。

您也有同样的问题

(float)1 / stk.pop() * stk.pop()

您的原始代码添加了一些调试:https://godbolt.org/z/xEKzeTzvn

修复版本:https://godbolt.org/z/oczef5hrj

© www.soinside.com 2019 - 2024. All rights reserved.