C++:是什么导致了这个堆栈粉碎错误?

C++: What is causing this stack smashing error?

本文关键字:堆栈 错误 是什么 C++      更新时间:2023-10-16

免责声明:我对C++的了解有限,因为他们从一所不教C++的大学转到另一所大学,在那里这是唯一教授的语言。

我正在尝试为在 54x54 的晶格中随机生成的 2D 集群实现盒计数方法。

其中一个要求是我们使用一维数组来表示二维正方形晶格,因此需要进行转换以将 x 和 y 值(分别为列和线(与数组的实际位置相关联。 变换是"i = x + y*N",其中N是方形晶格边的长度(在这种情况下,它将是54(,i是数组的位置。

简单地说,盒子计数方法涉及将网格拆分为逐渐变小的大正方形,并计算每个实例中包含聚类的数量。 对于较小的晶格尺寸,至少是我可以验证的那些,代码的工作方式(出于显而易见的原因,我甚至无法手动验证 10x10 的晶格(。但是,当我运行它时,盒子大小一直到 1/37,并给我一个"检测到堆栈粉碎"错误。

据我了解,该错误可能与数组大小有关,但我已经检查了访问数组的点,并确保它们在数组的实际尺寸范围内。

函数"boxTransform(int grid[], int NNew, intdiv("中的"for"是导致错误的原因,但我添加了我认为与之相关的其他函数。 代码的其余部分只是定义一个格子并隔离聚合,然后将其传递给 boxCounting(int grid[](,并创建一个.dat文件。这些工作正常。

为了将较大的数组"拟合"到较小的数组中,我将每个坐标 (x, y( 除以大数组与小数组上的正方形之比。这就是我的老师解释它的方式,如前所述,适用于较小的数组大小。

编辑:由于VTT的评论,我回去检查数组索引是否超出代码本身的界限。事实确实如此,这很可能是问题的根源。

编辑#2:这确实是问题的根源。计算中有一个轻微的错误,对于较小的晶格尺寸没有出现(或者我只是错过了它(。

//grid[] is an array containing the cluster
//that I want to analyze.
void boxCounting(int grid[]) {
//N is a global constant; it's the length of the
//side of the square lattice that's being analyzed.
//NNew is the side of the larger squares. It will
//be increased until it reaches N
for (int NNew = 1; N - NNew > 0; NNew++) {
int div = N/NNew;
boxTransform(grid, NNew, div);
}
}
void boxTransform(int grid[], int NNew, int div) {
int gridNew[NNew*NNew];
//Here the array elements are set to zero, which
//I understand C++ cannot do natively
for (int i = 0; i < NNew*NNew; i++) {
gridNew[i] = 0;
}
for (int row = 0; row < N; row++) {
for (int col = 0; col < N; col++) {
if (grid[col + row*N] == 1) {
//This is where the error occurs. The idea here is
//that if a square on the initial grid is occupied,
//the corresponding square on the new grid will have
//its value increased by 1, so I can later check
//how many squares on the larger grid are occupied
gridNew[col/div + (row/div)*NNew]++;
}
}
}
int boxes = countBox(gridNew, NNew);
//Creates a .dat file with the relevant values
printResult(boxes, NNew);
}
int countBox(int grid[], int NNew) {
int boxes = 0;
//Any array values that weren't touched remain at zero,
//so I just have to check that it's greater than zero
//to know if the square is occupied or not
for(int i = 0; i < NNew*NNew; i++) {
if(grid[i] > 0) boxes++;
}
return boxes;
}

不幸的是,这还不足以为您找到确切的问题,但我会尽力提供帮助。

有多种原因,您应该使用动态数组而不是您正在使用的固定大小的数组,除非您的练习需要它。 如果你一直在学习其他语言,你可能会认为固定数组已经足够好了,但它在C++中比在大多数语言中要危险得多。

  1. int gridNew[NNew*NNew];您应该知道,根据C++标准,这是无效的,只有 GCC 编译器才能使其工作。在C++中,您始终必须知道编译时固定数组的大小。这意味着您不能使用变量来声明数组。

  2. 您不断更新全局变量以跟踪数组的大小,这使您的代码非常难以阅读。您可能这样做是因为您知道一旦将数组传递给函数,就无法查询数组的大小。

对于这两个问题,动态数组是完美的解决方案。C++ 中的标准动态数组实现是 std::vector: https://en.cppreference.com/w/cpp/container/vector

创建向量时,可以定义其大小,也可以使用size()成员函数查询向量的长度。

更好的是:您可以使用at()函数而不是方括号 ([]( 来获取带有索引的元素,该索引会为您进行边界检查,如果您提供的索引超出边界,则会引发异常,这有助于定位此类错误。因为C++如果您只是简单地提供一个数组中不存在的索引,那么这是一种未定义的行为,这可能是您的问题。

我不想再写向量的任何特征,因为很容易找到有关如何做这些事情的例子,我只是想帮助你从哪里开始。

VTT 在他的评论中是正确的。将大数组放入较小数组的转换存在一个小问题,这使得索引超出范围。当我应该把它放在实际代码中时,我只在笔和纸上检查了这一点,这就是我没有注意到它的原因。由于他没有将其作为答案发布,因此我代表他这样做。

int gridNew[NNew*NNew];位有点像红鲱鱼,但我感谢这个教训,并将在将来编码时考虑到这一点 C++.