我正在研究一个RPN计算器,现在我的main.cpp和这些其他类文件应该采用一串代数运算,例如“3 + 4 / 2.34”,可以采用算术运算符,可读取双精度,整数,分数和混合分数(整数,单个空格,然后是分数)。
在命令控制台中我收到此错误:
ASSERT: "uint(i) < uint(size())" in file c:\QtSDK\Desktop\Qt\4.8.1\mingw\include
/QtCore/qstring.h, line 701
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Press <RETURN> to close this window...
我不太了解QT能够嗅出这个错误来自哪里,所以除了展示我的代码并希望有人可以帮助我之外我别无其他选择。有很多代码:/我已经排除了Fraction和Mixed类的头文件和源代码,因为那些没有使用qstring.h,这是编译器似乎在抱怨的内容。如果您认为这些是必需的,我可以发布它们。
据我所知,它与将无符号整数与整数进行比较有关,可能尝试将负int分配给uint?这是奇怪的部分,在main.cpp文件中,输入字符串是“1345/43143 - 2”,这会导致错误。此外,“3 + 4”也会导致错误。奇怪的是,如果我将输入字符串设置为“2341 +(23 ^ 4.421)/ 23/321 - 5 6/7”它可以工作,但没有其他输入字符串似乎工作。
Token.h
#ifndef TOKEN_H
#define TOKEN_H
#include "Mixed.h"
#include "Fraction.h"
class Token
{
public:
Token();
Token(const QString& Substring);
void SetIntPart(const QString& Substring);
void SetDoublePart(const QString& Substring);
void SetFractionPart(const QString& Substring);
void SetMixedPart(const QString& Substring);
void SetOperatorPart(const QString& Substring);
bool isDouble(const QString& Substring);
bool isInt(const QString& Substring);
bool isFraction(const QString& Substring);
bool isMixed(const QString& Substring);
bool isOperator(const QString& Substring);
bool isNumber()
{ return (inttoken || doubletoken || fractiontoken || mixedtoken); }
bool isLeftParen();
bool isRightParen();
bool isOperator();
int IntPart() { return intpart; }
double DoublePart() { return doublepart; }
Fraction FractionPart() { return fractionpart; }
Mixed MixedPart() { return mixedpart; }
char OperatorPart() { return operatorpart; }
bool IntToken() { return inttoken; }
bool DoubleToken() { return doubletoken; }
bool FractionToken() { return fractiontoken; }
bool MixedToken() { return mixedtoken; }
bool OperatorToken() { return operatortoken; }
QString toQString();
void Print(ostream& out) const;
friend ostream& operator<<(ostream& out, const Token& T);
private:
int intpart;
double doublepart;
Fraction fractionpart;
Mixed mixedpart;
char operatorpart;
bool inttoken;
bool doubletoken;
bool fractiontoken;
bool operatortoken;
bool mixedtoken;
void ClearBools();
void ClearParts();
void ClearAll() { ClearBools(); ClearParts(); }
};
#endif // TOKEN_H
Parser.h
#ifndef PARSER_H
#define PARSER_H
#include <iostream>
#include <cstdlib>
#include "Fraction.h"
#include "Mixed.h"
#include "Queue.h"
#include "Stack.h"
#include "Token.h"
class Parser
{
public:
Parser();
void LoadInputQueue(const QString& QS);
void LoadOutputQueue();
void CopyInputToString(QString &QS);
void CopyOutputToString(QString &QS);
bool isOperator(const QChar& Qch);
bool isSpace(const QChar& Qch);
bool isRightParen(const QChar& Qch);
bool isLeftParen(const QChar& Qch);
bool isParen(const QChar& Qch);
bool isDigit(const QChar& Qch);
void PrintInputQueue(ostream& out);
void PrintOutputQueue(ostream& out);
void PrintOperatorStack(ostream& out);
int precedence(Token T);
private:
Queue<Token> InputQueue;
Queue<Token> OutputQueue;
Stack<Token> OperatorStack;
void Tokenize(const QString& InputString, int n);
};
#endif // PARSER_H
的main.cpp
#include <QtCore/QCoreApplication>
#include <cstdlib>
#include <iostream>
#include "Token.h"
#include "Parser.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
/*cout << "Fractiontoken: " << A.FractionToken() << endl;
cout << "Fraction part: " << A.FractionPart() << endl;
cout << "Inttoken: " << A.IntToken() << endl;
cout << "Int part: " << A.IntPart() << endl;
cout << "Doubletoken: " << A.DoubleToken() << endl;
cout << "Double part: " << A.DoublePart() << endl;
cout << "Mixedtoken: " << A.MixedToken() << endl;
cout << "Mixed part: " << A.MixedPart() << endl;
cout << "Operatortoken: " << A.OperatorToken() << endl;
cout << "Operator part: " << A.OperatorPart() << endl;*/
QString inputstring = "1345/43143 - 2";
Parser P;
QString displaystring;
P.LoadInputQueue(inputstring);
P.CopyInputToString(displaystring);
cout << qPrintable(displaystring);
cout << endl;
P.LoadOutputQueue();
P.CopyOutputToString(displaystring);
cout << qPrintable(displaystring);
cout << endl;
return a.exec();
}
parser.cpp
#include "Parser.h"
enum PARENTHESIS_1{P1};
enum PARENTHESIS_2{P2};
bool Parser::isOperator(const QChar& Qch)
{
char ch = Qch.toAscii();
if (ch == '+' ||
ch == '-' ||
ch == '*' ||
ch == '/' ||
ch == '(' ||
ch == ')' ||
ch == '^' )
return 1;
return 0;
}
bool Parser::isSpace(const QChar& Qch)
{
if (Qch.toAscii() == ' ')
return 1;
return 0;
}
bool Parser::isLeftParen(const QChar& Qch)
{
char ch = Qch.toAscii();
if (ch == '(')
return 1;
return 0;
}
bool Parser::isRightParen(const QChar& Qch)
{
char ch = Qch.toAscii();
if (ch == ')')
return 1;
return 0;
}
bool Parser::isParen(const QChar& Qch)
{
if (isRightParen(Qch) || isLeftParen(Qch))
return 1;
return 0;
}
bool Parser::isDigit(const QChar &Qch)
{
char ch = Qch.toAscii();
if (ch > 47 && ch < 58)
return 1;
return 0;
}
Parser::Parser() : InputQueue(100), OutputQueue(100)
{
}
void Parser::Tokenize(const QString& InputString, int n)
{
if (n >= InputString.size())
return;
else
{
if (isOperator(InputString[n]))
{
QString temp;
temp.append(InputString[n]);
Token temptoken(temp);
InputQueue.enqueue(temptoken);
Tokenize(InputString, n+1);
}
else if (isSpace(InputString[n]))
Tokenize(InputString, n+1);
else
{
QString temp;
while (n < InputString.size() && !isSpace(InputString[n]) && !isParen(InputString[n]))
{
temp.append(InputString[n]);
n++;
}
if (isSpace(InputString[n]))
{
if (isDigit(InputString[n+1]))
{
temp.append(' ');
n++;
while (n < InputString.size() && !isSpace(InputString[n]) &&
!isParen(InputString[n]))
{
temp.append(InputString[n]);
n++;
}
Token temptoken(temp);
InputQueue.enqueue(temptoken);
Tokenize(InputString, n);
}
else if (isOperator(InputString[n+1]))
{
Token temptoken(temp);
InputQueue.enqueue(temptoken);
Tokenize(InputString, n+1);
}
}
else if (isParen(InputString[n]))
{
Token temptoken(temp);
InputQueue.enqueue(temptoken);
temp.clear();
temp.append(InputString[n]);
Token temptoken2(temp);
InputQueue.enqueue(temptoken2);
Tokenize(InputString, n+1);
}
}
}
}
int Parser::precedence(Token T)
{
if (T.OperatorToken())
{
char temp = T.OperatorPart();
if (temp == '^')
return 4;
if (temp == '*' || temp == '/')
return 3;
if (temp == '+' || temp == '-')
return 2;
}
return 1;
}
void Parser::LoadOutputQueue()
{
while (!InputQueue.empty())
{
Token temptoken;
InputQueue.dequeue(temptoken);
if (temptoken.isNumber())
OutputQueue.enqueue(temptoken);
else if (temptoken.isLeftParen())
OperatorStack.push(temptoken);
else if (temptoken.isRightParen())
{
while (!OperatorStack.empty() && !(OperatorStack.Peek()).isLeftParen())
{
Token temp;
OperatorStack.pop(temp);
OutputQueue.enqueue(temp);
}
if (!OperatorStack.empty() && (OperatorStack.Peek()).isLeftParen())
OperatorStack.pop(temptoken);
else if (OperatorStack.empty())
throw P1;
}
else if (temptoken.isOperator())
{
while (!OperatorStack.empty() && precedence(temptoken) < precedence(OperatorStack.Peek()))
{
Token temp;
OperatorStack.pop(temp);
OutputQueue.enqueue(temp);
}
OperatorStack.push(temptoken);
}
}
while (!OperatorStack.empty())
{
Token temptoken;
OperatorStack.pop(temptoken);
if (temptoken.isLeftParen())
throw P2;
OutputQueue.enqueue(temptoken);
}
}
//this function takes a QString (of chars) and from that builds its queue of tokens
void Parser::LoadInputQueue(const QString &QS)
{
Tokenize(QS,0);
}
void Parser::CopyOutputToString(QString &QS)
{
QString tempstring;
Token temptoken;
for (int i=OutputQueue.Size()-1; i>=0; i--)
{
temptoken = OutputQueue.Element(i);
tempstring.append(temptoken.toQString());
}
QS = tempstring;
}
void Parser::CopyInputToString(QString& QS)
{
QString tempstring;
Token temptoken;
for (int i=InputQueue.Size()-1; i>=0; i--)
{
temptoken = InputQueue.Element(i);
tempstring.append(temptoken.toQString());
}
QS = tempstring;
}
void Parser::PrintInputQueue(ostream& out)
{
out << InputQueue << endl;
}
void Parser::PrintOutputQueue(ostream& out)
{
out << OutputQueue << endl;
}
void Parser::PrintOperatorStack(ostream& out)
{
out << OperatorStack << endl;
}
token.cpp
#include "Token.h"
#include <QStringList>
enum TOKEN_EXCEPTIONS{UNKNOWN_TOKEN};
Token::Token()
{
}
Token::Token(const QString& Substring)
{
if (isInt(Substring))
SetIntPart(Substring);
else if (isDouble(Substring))
SetDoublePart(Substring);
else if (isFraction(Substring))
SetFractionPart(Substring);
else if (isMixed(Substring))
SetMixedPart(Substring);
else if (isOperator(Substring))
SetOperatorPart(Substring);
else
{
cout << qPrintable(Substring) << endl;
throw UNKNOWN_TOKEN;
}
}
void Token::SetIntPart(const QString& Substring)
{
ClearAll();
intpart = Substring.toInt();
inttoken = 1;
}
void Token::SetDoublePart(const QString& Substring)
{
ClearAll();
doublepart = Substring.toDouble();
doubletoken = 1;
}
void Token::SetFractionPart(const QString& Substring)
{
ClearAll();
QStringList Q;
Q = Substring.split('/');
Fraction frac(Q[0].toInt(),Q[1].toInt());
fractionpart = frac;
fractiontoken = 1;
}
void Token::SetMixedPart(const QString& Substring)
{
ClearAll();
QStringList Q1, Q2;
Q1 = Substring.split(' ');
QString wholepart = Q1[0];
Q2 = Q1[1].split('/');
QString numeratorstring = Q2[0];
QString denominatorstring = Q2[1];
Mixed M(wholepart.toInt(),numeratorstring.toInt(),denominatorstring.toInt());
mixedpart = M;
mixedtoken = 1;
}
void Token::SetOperatorPart(const QString& Substring)
{
ClearAll();
operatorpart = Substring[0].toAscii();
operatortoken = 1;
}
bool Token::isDouble(const QString& Substring)
{
int pointcount=0;
int intcount=0;
int pointloc=0;
for (int i=0; i<Substring.size(); i++)
{
if (isdigit(Substring[i].toAscii()))
intcount++;
if (Substring[i].toAscii() == '.')
{
pointcount++;
pointloc = i;
}
}
if (pointcount != 1)
return 0;
if (intcount != Substring.size() - 1)
return 0;
return 1;
}
bool Token::isInt(const QString& Substring)
{
if (Substring[0].toAscii() == '0')
return 0;
for (int i=0; i<Substring.size(); i++)
{
if (!isdigit(Substring[i].toAscii()))
return 0;
}
return 1;
}
bool Token::isFraction(const QString& Substring)
{
int slashcount=0;
int intcount=0;
int slashloc=0;
for (int i=0; i<Substring.size(); i++)
{
if (Substring[i].toAscii() == '/')
{
slashcount++;
slashloc = i;
}
if (isdigit(Substring[i].toAscii()))
intcount++;
}
if (slashcount != 1) // if there is not exactly 1 slash in substring
return 0;
if (intcount != Substring.size() - 1) //if the rest of the chars are not integers
return 0;
if (slashloc == 0 || slashloc == Substring.size() - 1) //if slash is at wrong location
return 0;
if (Substring[slashloc+1].toAscii() == '0' ||
Substring[0].toAscii() == '0')
return 0;
return 1;
}
bool Token::isMixed(const QString& Substring)
{
if (Substring[0].toAscii() == '0')
return 0;
int spacecount=0;
int slashcount=0;
int intcount=0;
int slashloc=0;
int spaceloc=0;
for (int i=0; i<Substring.size(); i++)
{
if (isspace(Substring[i].toAscii()))
{
spacecount++;
spaceloc = i;
}
if (isdigit(Substring[i].toAscii()))
intcount++;
if (Substring[i].toAscii() == '/')
{
slashcount++;
slashloc = i;
}
}
// cout << "spacecount: " << spacecount << endl;
// cout << "slashcount: " << slashcount << endl;
// cout << "intcount: " << intcount << endl;
// cout << "slashloc: " << slashloc << endl;
// cout << "spaceloc: " << spaceloc << endl;
if (spacecount != 1)
return 0;
if (slashcount != 1)
return 0;
if (intcount != Substring.size() - 2)
return 0;
if (slashloc == 0 || slashloc == Substring.size()-1)
return 0;
if (spaceloc == 0 || spaceloc == Substring.size()-1)
return 0;
if (slashloc < spaceloc)
return 0;
if (!isdigit(Substring[slashloc-1].toAscii()) || !isdigit(Substring[slashloc+1].toAscii()))
return 0;
if (!isdigit(Substring[spaceloc-1].toAscii()) || !isdigit(Substring[slashloc+1].toAscii()))
return 0;
return 1;
}
bool Token::isOperator(const QString& Substring)
{
if (Substring.size() != 1)
return 0;
if (Substring[0] == '+' ||
Substring[0] == '-' ||
Substring[0] == '*' ||
Substring[0] == '^' ||
Substring[0] == '/' ||
Substring[0] == '(' ||
Substring[0] == ')')
return 1;
return 0;
}
void Token::ClearBools()
{
mixedtoken = 0;
inttoken = 0;
doubletoken = 0;
fractiontoken = 0;
operatortoken = 0;
}
void Token::ClearParts()
{
intpart = 0;
doublepart = 0;
Fraction f(0);
fractionpart = f;
Mixed m(0);
mixedpart = m;
operatorpart = NULL;
}
QString Token::toQString()
{
QString tempstring;
if (inttoken)
{
QString temp;
temp.setNum(intpart);
tempstring.append('[');
tempstring.append(temp);
tempstring.append(']');
return tempstring;
}
else if (doubletoken)
{
QString temp;
temp.setNum(doublepart);
tempstring.append('[');
tempstring.append(temp);
tempstring.append(']');
return tempstring;
}
else if (fractiontoken)
{
Fraction F = fractionpart;
QString temp;
tempstring.append('[');
temp.setNum(F.Numerator());
tempstring.append(temp);
tempstring.append('/');
temp.setNum(F.Denominator());
tempstring.append(temp);
tempstring.append(']');
return tempstring;
}
else if (mixedtoken)
{
Mixed M = mixedpart;
QString temp;
tempstring.append('[');
temp.setNum(M.WholePart());
tempstring.append(temp);
tempstring.append(' ');
temp.setNum(M.Numerator());
tempstring.append(temp);
tempstring.append('/');
temp.setNum(M.Denominator());
tempstring.append(temp);
tempstring.append(']');
return tempstring;
}
else if (operatortoken)
{
tempstring.append('[');
tempstring.append(operatorpart);
tempstring.append(']');
}
else
throw UNKNOWN_TOKEN;
}
void Token::Print(ostream& out) const
{
if (inttoken)
{
out << intpart;
}
else if (doubletoken)
{
out << doublepart;
}
else if (fractiontoken)
{
out << fractionpart;
}
else if (mixedtoken)
{
out << mixedpart;
}
else if (operatortoken)
{
out << operatorpart;
}
else
throw 1;
}
ostream& operator<<(ostream& out, const Token& T)
{
T.Print(out);
return out;
}
bool Token::isLeftParen()
{
if (operatortoken && operatorpart == '(')
return 1;
return 0;
}
bool Token::isRightParen()
{
if (operatortoken && operatorpart == ')')
return 1;
return 0;
}
bool Token::isOperator()
{
if (operatortoken)
return 1;
return 0;
}
答案 0 :(得分:1)
我认为这肯定是错误的:
while (n < InputString.size() && !isSpace(InputString[n]) && !isParen(InputString[n]))
{
temp.append(InputString[n]);
n++;
}
if (isSpace(InputString[n]))
应该是:
while (n < InputString.size() && !isSpace(InputString[n]) && !isParen(InputString[n]))
{
temp.append(InputString[n]);
n++;
}
if (n < InputString.size() && isSpace(InputString[n]))
真正的错误可能是在其他地方没有读取所有代码,但类似的地方你运行到字符串结束然后访问后面的字符。
在调试器中运行代码,并在断言时查看代码中的代码。
答案 1 :(得分:1)
短篇小说 -
ASSERT: "uint(i) < uint(size())" in file c:\QtSDK\Desktop\Qt\4.8.1\mingw\include
/QtCore/qstring.h, line 701
这基本上意味着你在字符串长度上运行。它也可以是引用单位化或释放的存储区域的效果。
我最好的猜测是解析器试图读取输入字符串长度,这表明某些停止条件不符合。
了解这一点,你可能更容易找到解析器问题本身。
如果你有一个允许调试的环境(例如eclipse),那就去吧。如果没有,您可以尝试在代码的不同位置插入各种调试printf语句(我将从Parser开始)并查看它遇到错误的位置。
我查看了代码,但没有看到明显的问题。祝你好运!
答案 2 :(得分:0)
有很多地方可以访问字符(或类似的数组条目),而无需先检查索引:
void Parser::Tokenize(const QString& InputString, int n)
if (isSpace(InputString[n]))
{
if (isDigit(InputString[n+1]))
...
else if (isOperator(InputString[n+1]))
void Token::SetFractionPart(const QString& Substring)
Fraction frac(Q[0].toInt(),Q[1].toInt());
void Token::SetMixedPart(const QString& Substring)
QString wholepart = Q1[0];
Q2 = Q1[1].split('/');
QString numeratorstring = Q2[0];
QString denominatorstring = Q2[1];
void Token::SetOperatorPart(const QString& Substring)
operatorpart = Substring[0].toAscii();
bool Token::isInt(const QString& Substring)
if (Substring[0].toAscii() == '0')
bool Token::isMixed(const QString& Substring)
if (Substring[0].toAscii() == '0')
通过在调试器中运行并查看stacktrace
,您可以更轻松地找到特定问题答案 3 :(得分:0)
以下是您的代码的一些观察结果:
false
或true
返回bool
。您可以,而不是与每个操作员角色进行比较 搜索它:
bool is_operator(char c)
{
static const char operators_text[] = "+-/*()^";
std::string operators_str(operators_text);
return operators_str.find_first_of(c) != std::string::npos;
}
您的 is-a 功能可以简化:
bool Parser :: isSpace(const QChar&amp; qch)
{
return qch =='';
}
让您的isDigit更具可读性:
bool Parser :: isDigit(const Qchar&amp; qch)
{
return(qch&gt; ='0')|| (qch&lt; ='9');
}
或使用std::isdigit()
。