【问题标题】:Getting "heap corruption detected" while calling delete[] on couple of arrays in my class - C++在我的班级中的几个数组上调用 delete[] 时得到“检测到堆损坏” - C++
【发布时间】:2020-02-07 05:06:01
【问题描述】:

我有以下代码,我在类的构造函数中为三个 int* 分配内存。稍后在类的析构函数中删除它。我在析构函数中删除两个 int* 时遇到问题(我已将 cmets 放在下面的代码中,我遇到了问题):

#define CAP 3
class SetOfStacks
{
private:
    int* a1;
    int* a2;
    int* a3;
    int index = -1;
public:
    void push(int data);
    SetOfStacks()
    {
        a1 = new int[CAP];
        a2 = new int[CAP];
        a3 = new int[CAP];
    }
    ~SetOfStacks()
    {
        delete [] a1; //This works just fine
        delete [] a2; //heap corruption here
        delete [] a3; //heap corruption here
    }
};

void SetOfStacks::push(int data)
{
    if (index >= 3 * CAP)
    {
        cout << "stack overflow" << endl;
        return;
    }
    if(index>=-1 && index<=1)
    {
        index++;
        a1[index] = data;
    }
    else if (index >1  && index<=4)
    {
        index++;
        a2[index] = data;
    }
    else if (index >4 && index<=7)
    {
        index++;
        a3[index] = data;
    }
}


int main()
{
    SetOfStacks s;
    s.push(10);
    s.push(20);
    s.push(30);;
    s.push(40);
    s.push(50);
    s.push(60);
    s.push(70);
    s.push(80);
    s.push(90);

    return 0;
}

我多次调试代码,但是,我不确定为什么在删除 [] a2 和删除 [] a3 时会出现 HEAP CORRUPTION。执行 delete[] a1 工作得很好。我在 delete[] a2 和 delete[] a3 上收到以下错误:

您知道我为什么会收到此错误,以及是什么原因造成的(我很困惑为什么删除 a1 可以正常工作,但删除 a2 和 a3 会出现此错误 - 尽管它们在代码中几乎经历了相同的逻辑)?

【问题讨论】:

  • if (index &gt;4 &amp;&amp; index&lt;=7) ... a3[index] = data; - 这是你的问题。您在a3 范围之外写入数据(a2 也是如此)。
  • a2[index % 3]a3[index % 3]来修复它...它将保持index在0-2以内

标签: c++ arrays delete-operator


【解决方案1】:

您的所有数组的长度均为CAP,即3(根据您的 if 语句判断),但在写入数组时您不会将索引相对化。

    else if (index >4 && index<=7)
    {
        index++;
        a3[index] = data;
    }

在这些行中,您可以将最大为 8 的索引写入数组。 这就是您收到错误的原因:

CRT 检测到应用程序在堆缓冲区结束后写入内存。

您可以在使用index % CAP 写入索引时使用模运算符来解决此问题。 为使其与任何 CAP 正常工作,您的 if 语句还应使用 &gt;= N * CAP 作为边界。

   else if (index >= 2 * CAP) // no upper check needed in an if-else chain
    {
        a3[index++ % CAP] = data; // you can also do index++ after
    }

【讨论】:

  • @J.Schultke,这次我在 main 中做了所有的调试,在 main 中只有一个 int* a。因此,当我执行int* a=new int[3](主要)时,会保留 3 个 int 块(3 个块,每个块 4 个字节)。但是,我可以写信给a[0]a[1]a[2],但不能超出此范围。这是因为 C++ 总是从索引 0 开始。我正确吗?为什么我不能写信给a[3]a[4]a[5] 而写给a[0]a[1]a[2],因为保留了 3 个内存块,而我正在写 3 个内存块在这两种情况下?另外,为什么问题会在delete[] a 之后出现,而不是在分配给a[3] 本身时出现?
  • 如果每个块保留 4 个字节,您应该能够访问索引0..3,因此有 4 个不同的索引。不允许访问超出第一个块的内存,因为在堆上,您的内存可能在任何地方。如果您在堆上一个接一个地创建两个数组,它们可能位于完全不同的位置。但是,即使您将它们分配在堆栈上,这也将是未定义的行为。它可能会在稍后出现,因为您的调试器可能只在删除内存时进行堆完整性检查(出于性能原因)。但这只是猜测。
  • 你也可以像int *a = new int[3 * CAP];这样声明一个伪二维数组,这样内存是连续的,你不需要手动将所有东西排序到这些块中。
【解决方案2】:

index 超出了您的数组范围:

if(index>=-1 && index<=1)
{
    index++;
    a1[index] = data; // index can be 0, 1 or 2 (fine)
}
else if (index >1  && index<=4)
{
    index++;
    a2[index] = data; // index can be 3, 4 or 5 (all out of range)
    // This fixes it:
    // a2[index - 3] = data; // index can now only be 0, 1 or 2
}
else if (index >4 && index<=7)
{
    index++;
    a3[index] = data; // index can be 6, 7 or 8 (all out of range)
    // This fixes it:
    // a3[index - 6] = data; // index can now only be 0, 1 or 2
}

我还建议使条件更能代表所使用的实际索引,以便更容易发现这种错误:

if(0 <= index && index < 3) {
    a1[index++] = data;
} else if (index < 6) {
    a2[index++ - 3] = data
} else if (index < 9) {
    a3[index++ - 6] = data;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-28
    • 2020-10-02
    • 2013-07-06
    • 2018-03-26
    • 1970-01-01
    • 2014-11-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多