first-time user and it seems from other posts to be a case-by-case basis. Well, I am a self-taught programmer of the C++ language. So, I finally learned about dynamically allocated memory and began thinking of new ways of programming a calculator using CLI to input a single string of text and pump out an answer. It seemed like a good jumping off point for the project and I began working on a solution. The following are my results:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string strInput;
cin >> strInput;
int nOperatorCount = 0;
for(int i = 0; i<(strInput.size());i++)
{
if(strInput[i]=='+'||strInput[i]=='-'||strInput[i]=='*'||strInput[i]=='/')
nOperatorCount++;
}
int *pnOperatorLocation = new int[nOperatorCount+1];
int *pnOperatorType = new int[nOperatorCount];
float *pnExpressions = new float[nOperatorCount + 1];
pnOperatorLocation[0] = -1;
for(int i=0,j=0; i<(strInput.size());i++)
{
if(strInput[i]=='+')
{
pnOperatorLocation[j+1] = i;
pnOperatorType[j] = 0;
pnExpressions[j] = atoi((strInput.substr(pnOperatorLocation[j]+1,i)).c_str());
j++;
}
if(strInput[i]=='-')
{
pnOperatorLocation[j+1] = i;
pnOperatorType[j] = 1;
pnExpressions[j] = atoi((strInput.substr(pnOperatorLocation[j]+1,i)).c_str());
j++;
}
if(strInput[i]=='*')
{
pnOperatorLocation[j+1] = i;
pnOperatorType[j] = 2;
pnExpressions[j] = atoi((strInput.substr(pnOperatorLocation[j]+1,i)).c_str());
j++;
}
if(strInput[i]=='/')
{
pnOperatorLocation[j+1] = i;
pnOperatorType[j] = 3;
pnExpressions[j] = atoi((strInput.substr(pnOperatorLocation[j]+1,i)).c_str());
j++;
}
if(i==(strInput.size()-1))
pnExpressions[j] = atoi((strInput.substr(pnOperatorLocation[j]+1,i+1)).c_str());
}
for(int i=0;i<nOperatorCount+1;i++)
{
cout << "pnExpressions[" << i << "]: " << pnExpressions[i] << endl;
}
int nOperationsCount = 0;
for(int i=0;i<nOperatorCount;i++)
{
if(pnOperatorType[i]==2||pnOperatorType[i]==3)
{
if(pnOperatorType[i+1]==0||pnOperatorType[i+1]==1)
nOperationsCount++;
else if((i+1)==nOperatorCount)
nOperationsCount++;
}
}
cout << "nOperationsCount: " << nOperationsCount << endl;
float *pnNewExpressions = new float[nOperationsCount];
for(int i=0,j=0;i<nOperatorCount;i++)
{
if(pnOperatorType[i]==2)
{
pnNewExpressions[j] = pnExpressions[i] * pnExpressions[i+1];
if(pnOperatorType[i+1]==2||pnOperatorType[i+1]==3)
{
for(int k=i;k<nOperatorCount-i;k++)
{
if(pnOperatorType[k+1]==2)
pnNewExpressions[j] = pnNewExpressions[j] * pnExpressions[k+2];
else if(pnOperatorType[k+1]==3)
pnNewExpressions[j] = pnNewExpressions[j] / pnExpressions[k+2];
else
break;
if(k+1>=nOperatorCount)
break;
}
}
j++;
}
if(pnOperatorType[i]==3)
{
pnNewExpressions[j] = pnExpressions[i] / pnExpressions[i+1];
if(pnOperatorType[i+1]==2||pnOperatorType[i+1]==3)
{
for(int k=i;k<nOperatorCount-i;k++)
{
if(pnOperatorType[k+1]==2)
pnNewExpressions[j] = pnNewExpressions[j] * pnExpressions[k+2];
else if(pnOperatorType[k+1]==3)
pnNewExpressions[j] = pnNewExpressions[j] / pnExpressions[k+2];
else
break;
if(k+1>=nOperatorCount)
break;
}
}
j++;
}
if(i+1>=nOperatorCount)
break;
}
for(int i=0;i<nOperationsCount;i++)
{
cout << "pnNewExpressions[" << i << "]: " << pnNewExpressions[i] << endl;
}
float fEvaluation;
if(pnOperatorType[0]==2||pnOperatorType[0]==3)
fEvaluation = pnNewExpressions[0];
else
fEvaluation = pnExpressions[0];
cout << "fEvaluation: " << fEvaluation << endl;
for(int i=0,j=1;i<nOperatorCount;i++)
{
if(pnOperatorType[i]==0)
{
if(pnOperatorType[i+1]==2||pnOperatorType[i+1]==3)
{
fEvaluation = fEvaluation + pnNewExpressions[j];
j++;
cout << "fEvaluation: " << fEvaluation << endl;
}
else
{
fEvaluation = fEvaluation + pnExpressions[i+1];
cout << "fEvaluation: " << fEvaluation << endl;
}
}
if(pnOperatorType[i]==1)
{
if(pnOperatorType[i+1]==2||pnOperatorType[i+1]==3)
{
fEvaluation = fEvaluation - pnNewExpressions[j];
j++;
cout << "fEvaluation: " << fEvaluation << endl;
}
else
{
fEvaluation = fEvaluation - pnExpressions[i+1];
cout << "fEvaluation: " << fEvaluation << endl;
}
}
}
cout << "fEvaluation: " << fEvaluation << endl;
delete[] pnOperatorLocation;
delete[] pnNewExpressions;
delete[] pnOperatorType;
delete[] pnExpressions;
system("pause");
return 0;
}
I'm so so SO sorry if you read through all that, but I've been working on a second copy that's been boiled down and a lot less complicated, but I'd figure why this one stopped working all of a sudden. It was working for about 10-15 uses and the I used an input such as "2*3*4+2*3+2" and it returned "CORRUPTION HEAP DETECTED: after normal block #184". So my question is does anyone have any idea how I can debug this based off that error-message? If not, can anyone find why my code works for simple equations like 1+1 and 8*8, but not the long complex ones like I intended it to?
The issue is this section of code:
for (int i = 0, j = 0; i < nOperatorCount; i++)
{
if (pnOperatorType[i] == 2)
{
pnNewExpressions[j] = pnExpressions[i] * pnExpressions[i + 1]; // <<--- Error
The subscript j
is out of bounds in the loop for the input of 2*3*4+2*3+2
.
But here is the reason why I found the error quickly -- I replaced all of those calls to new[]
and delete[]
with std::vector
. Since you're using Visual Studio (the error is a VS error), the DEBUG
version does automatic checking for vector array bounds errors. The error box that shows up gives you a subscript out of range
error, and thus the VS IDE goes right to the line where the violation occurs.
Now, the std::vector::operator[]
does not check bounds in a release
version, and in general operator []
is not supposed to do so. However the debugging libraries for VS turns on this check. So you can say I am taking advantage of what Visual Studio offers in terms of debugging help. But I was only afforded this once I changed to using std::vector
.
The vector::at()
function serves the same purpose as using []
, but it gives you the range checking, regardless of whether you are running a release or debug version. I didn't replace the calls with at()
here, but if for some reason []
didn't find the error, I could always change the []
to at()
calls in the code until I get an error generated.
Here is a quick synopsis of the changes:
#include <iostream>
#include <string>
#include <vector>
//...
std::vector<int> pnOperatorLocation(nOperatorCount + 1);
std::vector<int> pnOperatorType(nOperatorCount);
std::vector<float> pnExpressions(nOperatorCount + 1);
//...
std::vector<float> pnNewExpressions(nOperationsCount);
In addition, all of the calls to delete[]
are no longer necessary.
Does this fix the error? No. I didn't want to check your algorithm/logic in trying to solve the equation. You still need to put in that effort to figure out what the purpose of that loop is, and why j
goes out of bounds. However it does show that merely using modern C++ techniques can be advantageous. Using new[]
and delete[]
to create dynamic arrays is "old fashioned" and really not necessary, unless you really do need to use it.
Basically, you need to ask yourself -- are you trying to code an equation solver? If the answer is "yes", then use the tools available to create one (such as std::vector
) and move on with solving "easy" bugs, instead of fighting with using pointers and putting in a lot of effort in maintaining dynamic arrays correctly.