对象周围的堆栈已损坏

stack around object was corrupted

本文关键字:已损坏 堆栈 周围 对象      更新时间:2023-10-16

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

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

错误变量"obj"周围的堆栈已损坏。

如果我移除arr2 obj;,那么它工作正常。类本身或ctor elem[5]=(0,0,0,0,0);中的语句有什么问题吗我尝试用{}在main中定义一个数组,结果很好。我不知道为什么它在课堂上失败了。

int arr4[4]={1,2,3,4}; //OK
int elem[5]; // Represents that the array is of size 5 

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

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

(共五个元素(

elem[5]越界。

您需要考虑有两个不同的构造在这里工作。

初始化

//                  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元素,而不是声明一个名为elem的大小为5的新数组

当您改用(0, 0, 0, 0, 0)时,错误就会消失,因为这是一个计算结果为0的表达式,并且您可以将0分配给int数组的元素。

不幸的是,您这样做是针对一个不存在的元素,因为elem[5]超出了界限。它是一个五元素数组中的第六个元素。


不能使用initializer语法一下子分配给数组的所有元素是C和C++的限制。

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

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

…这无论如何都要好得多。


幸运的是,你犯了另一个非常方便的罪行:你实际上确实想要初始化,尽管目前你是在构造函数内部赋值。要初始化类成员,您必须使用构造函数的成员初始化器列表,而且,碰巧的是,构造函数的成员-初始化器列表使我们能够使用初始化器语法:

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

…或者,更简单地说:

arr2()
    : elem{}
{}

分配

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

在数组中的第六个位置写一个零(阅读逗号运算符((请记住,数组索引是基于零的(,它是数组末尾之外的一个。写入超出数组的边界会导致未定义的行为

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

class arr2
{
    int elem[5];
public:
    arr2()
        : elem{}
    {}
};

以上将值初始化数组,这意味着数组中的每个元素也将被值初始化,对于int值初始化,将其设置为0


为了扩展您得到的错误,现在几乎所有的系统和编译器都在堆栈上存储本地变量,其中包括main函数中的变量obj。将对象放置在堆栈上也会将其成员变量放置在堆栈中。如果您在数组的边界外写入,那么您也会在没有权限的堆栈内存上写入,从而损坏堆栈。

这并不能达到您的预期:

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

您为索引5(越界(处的元素指定值0。您不分配初始值设定项列表,而是分配一系列中间带有逗号运算符的零(返回每个调用的第二个值(,然后返回最右边的零。

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

使用{}会引发错误,因为{}只能用于数组的初始化,而不能用于赋值。

同样,上面的语句并没有将所有数组元素赋值为零,而是试图将一个零赋值给elem[5],这实际上超出了数组的边界。数组从elem[0]开始,到elem[4]结束。

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

因为你正在破坏这段记忆。你有例外。