如何调试我的"heap corruption"?(C++)

How do I debug my "heap corruption"? (C++)

本文关键字:corruption C++ heap 何调试 调试 我的      更新时间:2023-10-16

第一次使用,从其他帖子来看,这似乎是一个个案。嗯,我是一个自学成才的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;
}

如果你通读了所有这些,我非常抱歉,但我一直在写第二本,它被简化了,没有那么复杂,但我想知道为什么这本突然停止了工作。它工作了大约10-15次,我使用了一个输入,如"2*3*4+2*3+2",并返回"CORRUPTION HEAP DETECTED:在正常块#184之后"。所以我的问题是,有人知道我如何根据错误消息进行调试吗?如果没有,有人能找到为什么我的代码适用于1+1和8*8这样的简单方程,而不适用于我想要的长复杂方程吗?

问题是这段代码:

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的输入是越界的。

但这就是我很快发现错误的原因——我用std::vector替换了所有对new[]delete[]的调用。由于您使用的是Visual Studio(错误是VS错误),DEBUG版本会自动检查向量数组边界错误。显示的错误框会给您一个subscript out of range错误,因此VS IDE会直接转到发生冲突的行。

现在,std::vector::operator[]release版本中不检查边界,通常operator []也不应该这样做。但是VS的调试库启用了此检查。所以你可以说我在利用VisualStudio提供的调试帮助。但只有当我改为使用std::vector时,我才得到这个。

vector::at()函数的作用与使用[]相同,但它为您提供了范围检查,无论您运行的是发行版还是调试版。我在这里没有用at()替换这些调用,但如果由于某种原因[]没有发现错误,我总是可以在代码中将[]更改为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);

此外,对delete[]的所有调用都不再是必需的。

这能纠正错误吗?不,我不想在解方程时检查你的算法/逻辑。您仍然需要努力弄清楚这个循环的目的是什么,以及为什么j会越界。然而,它确实表明,仅仅使用现代C++技术可能是有利的。使用new[]delete[]来创建动态数组是"过时的",而且实际上没有必要,除非你真的需要使用它

基本上,你需要问问自己——你在试图编写一个方程求解器的代码吗?如果答案是"是",那么使用可用的工具来创建一个(如std::vector),并继续解决"简单"的错误,而不是使用指针和投入大量精力来正确维护动态数组。