对象周围的堆栈已损坏

时间:2015-09-25 10:15:38

标签: c++

我有以下一段代码,在运行抛出错误之后:

class arr2{
int count;
public:
    int elem[5];
    arr2()
    {
        count=-1;
        elem[5]=(0,0,0,0,0); //{} throws error i dont know why
    }
};
int main()
{
    arr2 obj;

    vector<int> vec;
    vec.assign(10,42);
    vector<int> ::iterator itr=vec.begin();
    for(;itr!=vec.end();++itr){
        cout<<*itr<<endl;       
    }

    return 0;
}

ERROR 围绕变量&#39; obj&#39;已经腐败了。

如果我删除arr2 obj;,那么它可以正常工作。 类本身或ctor elem[5]=(0,0,0,0,0);中的语句是否有任何错误 我尝试在main中用{}定义一个数组,它工作正常。在课堂上我不知道为什么会失败。

int arr4[4]={1,2,3,4}; //OK

5 个答案:

答案 0 :(得分:3)

int elem[5]; // Represents that the array is of size 5 

由于数组索引以0开头,因此可用的数组索引为:

  • elem[0]
  • elem[1]
  • elem[2]
  • elem[3]
  • elem[4]

(共五个要素)

elem[5]超出范围。

答案 1 :(得分:2)

作业

elem[5]=(0,0,0,0,0);

在数组的第六个处写一个零(读the comma operator)(记住数组索引是从零开始的),这是超出数组末尾的一个。超出数组范围的写入会导致undefined behavior

有几种方法可以初始化数组,最简单的是构造函数初始化列表:

class arr2
{
    int elem[5];

public:
    arr2()
        : elem{}
    {}
};

以上将value-initialize数组,这意味着数组中的每个元素也将进行值初始化,而int值初始化将其设置为0

为了扩展您所获得的错误,几乎所有系统和编译器都会在堆栈中存储局部变量,其中包括obj函数中的变量main。将对象放在堆栈上也会将其成员变量放在堆栈上。如果你写出数组的边界,那么你也写在堆栈内存上,你没有权利,因此破坏了堆栈。

答案 2 :(得分:2)

你需要考虑这里有两种截然不同的结构。

初始化

//                  initialiser
//                      |
//  name ("elem")       |
//      |               |
//     ▼▼▼▼    ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼
   int elem[5] = {0, 0, 0, 0, 0};
// ▲▲▲     ▲▲▲
//   \      /
//    \    /
//     \  /
//  type (int[5])

分配

//         new element value
//                |
// name ("elem")  |
//     |          |
//    ▼▼▼▼      ▼▼▼▼▼
      elem[n] = 12345;
//        ▲▲▲ ▲
//         |  |
//         | assignment operator
//         |
//     index (n)

您的问题与您在main或类定义中编写代码无关;问题是您正在尝试编写赋值,就像它是初始化一样。

  • 初始化{0, 0, 0, 0, 0}根本无法用于作业
  • 当您编写elem[5]而不是int elem[5]时,您将命名elem的6 th 元素,而不是声明一个名为5的新数组elem

当您使用(0, 0, 0, 0, 0)时错误消失,因为这是an expression that evaluates to 0,您可以将0分配给int数组的元素。

不幸的是,你正在对一个不存在的元素这样做,因为elem[5]超出范围。这是五元素数组中假设的第六个元素。

无法使用初始化语法一次性分配给所有数组的元素是C和C ++的限制。

要在任意位置分配数组,您必须在循环中逐个分配它们,或者使用填充函数:

std::fill(std::begin(elem), std::end(elem), 0);

......无论如何都要好得多。

幸运的是,你犯了另一个非常方便的犯罪:你实际上想要初始化,即使你现在正在构造函数体内进行分配。 To initialise class members, you must use the constructor's member-initialiser list并且,实际上,构造函数的成员初始化列表使我们能够使用初始化语法:

arr2()
    : elem{0, 0, 0, 0, 0}
{}

......或者更简单:

arr2()
    : elem{}
{}

答案 3 :(得分:0)

这不符合您的期望:

elem[5]=(0,0,0,0,0);

您在索引5(超出范围)中分配值为0.您不分配初始化列表,而是分配一系列零,其间有逗号运算符(返回第二个)每次调用的价值),然后返回最右边的零。

答案 4 :(得分:0)

 elem[5]=(0,0,0,0,0); //{} throws error i dont know why

使用{}抛出错误,因为{}必须仅用于数组的初始化,而不是用于赋值。

上面的语句也没有将所有数组元素分配给零,而是尝试将一个零分配给elem [5],这实际上超出了数组的边界。 你的数组从elem [0]开始,到elem [4]结束。

elem [5]实际上是指下面定义的向量的地址。        矢量vec;

因为你正在腐蚀这段记忆。你有例外。