我尝试在 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;
}
在
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