如何调试“堆损坏”? (C ++)

时间:2014-09-11 02:04:10

标签: c++ debugging calculator heap-corruption

首次使用的用户,其他帖子似乎是个案基础。好吧,我是一名自学成才的C ++语言程序员。因此,我终于了解了动态分配的内存,并开始考虑使用CLI编程计算器的新方法来输入单个文本字符串并提供答案。这似乎是该项目的一个很好的起点,我开始研究解决方案。以下是我的结果:

#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;
}

我很抱歉,如果你仔细阅读了所有内容,但是我一直在制作第二份副本,这些副本已经被简化了,而且复杂程度要低得多,但我还是这样。 d想为什么这个突然停止工作。它适用于大约10-15次使用,我使用了输入,例如&#34; 2 * 3 * 4 + 2 * 3 + 2&#34;它返回&#34;腐败堆检测:正常块#184&#34;。所以我的问题是有没有人知道如何根据该错误消息调试这个?如果没有,任何人都可以找到为什么我的代码适用于简单的方程式,如1 + 1和8 * 8,但不是像我想要的那样长的复杂方程式?

1 个答案:

答案 0 :(得分:0)

问题是这部分代码:

for (int i = 0, j = 0; i < nOperatorCount; i++)
{
    if (pnOperatorType[i] == 2)
    {
        pnNewExpressions[j] = pnExpressions[i] * pnExpressions[i + 1]; // <<--- Error 

下标j超出了2*3*4+2*3+2输入的循环范围。

但这就是为什么我很快发现错误的原因 - 我用[{1}}将所有这些来电替换为new[]delete[]。由于您正在使用Visual Studio(错误是VS错误),std::vector版本会自动检查向量数组边界错误。显示的错误框会出现DEBUG错误,因此VS IDE会直接进入违规行。

现在,subscript out of range不检查std::vector::operator[]版本中的边界,一般release不应该这样做。但是,VS的调试库会启用此检查。所以你可以说我正在利用Visual Studio在调试帮助方面提供的功能。但是,一旦我改为使用operator [],我就得到了这个。

std::vector函数与使用vector::at()的功能相同,但无论您是在运行发行版还是调试版,它都会为您提供范围检查。我在这里没有用[]替换来电,但如果由于某种原因at()没有找到错误,我可以随时将[]更改为{{1在代码中调用,直到我生成错误。

以下是这些变化的简要概要:

[]

此外,不再需要拨打at()的所有电话。

这是否可以解决错误?不,我不想在尝试解决方程时检查你的算法/逻辑。您仍然需要付出努力来弄清楚该循环的目的是什么,以及为什么#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); 超出界限。然而,它确实表明仅使用现代C ++技术可能是有利的。使用delete[]j来创建动态数组是老式的#34;除非你真的需要使用它,否则真的没必要。

基本上,您需要问问自己 - 您是否正在尝试编码方程求解器?如果答案是&#34;是&#34;,那么使用可用的工具创建一个(例如new[])并继续解决&#34; easy&#34;错误,而不是使用指针和正确维护动态数组的努力。