简体   繁体   English

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

[英]C++: What is causing this stack smashing error?

Disclaimer: I have limited knowledge of C++ due to switching from a college where they didn't teach C++ to another where it was the only language that was taught.免责声明:我对 C++ 的了解有限,因为我从一所不教授 C++ 的大学转到另一所教授唯一语言的大学。

I'm trying to implement the box counting method for a randomly generated 2D cluster in a lattice that's 54x54.我正在尝试在 54x54 的格子中为随机生成的 2D 集群实现盒子计数方法。

One of the requirements is that we use a 1D array to represent the 2D square lattice, so a transformation is required to associate x and y values (columns and lines, respectively) to the actual positions of the array.其中一个要求是我们使用一维数组来表示二维方格,因此需要进行转换以将 x 和 y 值(分别为列和行)与数组的实际位置相关联。 The transformation is "i = x + y*N", with N being the length of the side of the square lattice (in this case, it would be 54) and i being the position of the array.转换为“i = x + y*N”,其中 N 是方格的边长(在本例中为 54),i 是数组的 position。

The box-counting method, simply put, involves splitting a grid into large squares that get progressively smaller and counting how many contain the cluster in each instance.简单地说,box-counting 方法涉及将网格分成逐渐变小的大方块,并计算每个实例中有多少包含集群。 The code works in the way that it should for smaller lattice sizes, at least the ones that I could verify (for obvious reasons, I can't verify even a 10x10 lattice by hand).该代码的工作方式应该适用于较小的格子尺寸,至少是我可以验证的那些(出于显而易见的原因,我什至无法手动验证 10x10 格子)。 However, when I run it, the box size goes all the way to 1/37 and gives me a "stack smashing detected" error.但是,当我运行它时,盒子大小一直到 1/37,并给我一个“检测到堆栈粉碎”错误。

From what I understand, the error may have something to do with array sizes, but I've checked the points where the arrays are accessed and made sure they're within the actual dimensions of the array.据我了解,该错误可能与数组大小有关,但我检查了访问 arrays 的点,并确保它们在数组的实际尺寸范围内。

A "for" in the function "boxTransform(int grid[], int NNew, int div)" is responsible for the error in question, but I added other functions that I believe are relevant to it. function "boxTransform(int grid[], int NNew, int div)" 中的“for”是导致该错误的原因,但我添加了我认为与之相关的其他函数。 The rest of the code is just defining a lattice and isolating the aggregate, which is then passed to boxCounting(int grid[]), and creating a.dat file.代码的 rest 只是定义一个格子并隔离聚合,然后将其传递给 boxCounting(int grid[]),并创建一个.dat 文件。 Those work fine.那些工作正常。

To "fit" the larger array into the smaller one, I divide each coordinate (x, y) by the ratio of squares on the large array to the small array.为了将较大的数组“拟合”到较小的数组中,我将每个坐标 (x, y) 除以大数组与小数组上的正方形的比率。 This is how my teacher explained it, and as mentioned before, works fine for smaller array sizes.这就是我的老师解释它的方式,并且如前所述,它适用于较小的数组大小。

EDIT: Thanks to a comment by VTT, I went back and checked if the array index goes out of bounds with the code itself.编辑:感谢 VTT 的评论,我回去检查数组索引是否超出了代码本身的范围。 It is indeed the case, which is likely the origin of the problem.确实如此,这很可能是问题的根源。

EDIT #2: It was indeed the origin of the problem.编辑#2:这确实是问题的根源。 There was a slight error in the calculations that didn't appear for smaller lattice sizes (or I just missed it).较小的晶格尺寸没有出现计算中的轻微错误(或者我只是错过了它)。

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

Unfortunately this is not enough information to find the exact problem for you but I will try to help.不幸的是,这些信息不足以为您找到确切的问题,但我会尽力提供帮助。

There are like multiple reasons that you should use a dynamic array instead of the fixed size arrays that you are using except if it's required in your exercise.您应该使用动态数组而不是您正在使用的固定大小 arrays 的原因有多种,除非您的练习需要它。 If you've been learning other languages you might think that fixed array is good enough, but it's far more dangerous in C++ than in most of the languages.如果您一直在学习其他语言,您可能会认为固定数组已经足够好,但在 C++ 中它比在大多数语言中危险得多。

  1. int gridNew[NNew*NNew]; You should know that this is not valid according to C++ standard, only the GCC compiler made it work.您应该知道,根据 C++ 标准,这是无效的,只有 GCC 编译器使其工作。 In C++ you always have to know the size of the fixed arrays in compile time.在 C++ 中,您始终必须在编译时知道固定 arrays 的大小。 Which means you can't use variables to declare an array.这意味着您不能使用变量来声明数组。

  2. You keep updating global variables to track the size of the array which makes your code super hard to read.您不断更新全局变量以跟踪数组的大小,这使您的代码非常难以阅读。 You are probably doing this because you know that you are not able to query the size of the array once you pass it to a function.您这样做可能是因为您知道一旦将数组传递给 function,就无法查询数组的大小。

For both of these problems a dynamic array is the perfect solution.对于这两个问题,动态数组都是完美的解决方案。 The standard dynamic array implementation in C++ is the std::vector: https://en.cppreference.com/w/cpp/container/vector C++ 中的标准动态数组实现是 std::vector: https://en.cppreference.com/w/cpp/container/vector

When you create a vector you can define it's size and also you can query the length of the vector with the size() member function.创建向量时,您可以定义它的大小,也可以使用size()成员 function 查询向量的长度。

Even better: You can use the at() function instead of the square brackets( [] ) to get and element with an index which does bounds check for you and throws an exception if you provided an index which is out of bounds which helps a lot to locate these kind of errors.更好的是:您可以使用at() function 而不是方括号 ( [] ) 来获取具有索引的元素,该索引会为您进行边界检查,如果您提供的索引超出范围,则会引发异常,这有助于很多来定位这些类型的错误。 Because in C++ if you just simply provide an index which does not exist in an array it is an undefined behaviour which might be your problem.因为在 C++ 中,如果您只是提供一个数组中不存在的索引,则可能是您的问题的未定义行为。

I wouldn't like to write any more features of the vector because it's really easy to find examples on how to do these things, I just wanted to help you where to start.我不想再写向量的任何特性,因为很容易找到关于如何做这些事情的示例,我只是想帮助你从哪里开始。

VTT was right in his comment. VTT 在他的评论中是正确的。 There was a small issue with the transformation to fit the large array into the smaller one that made the index go out of bounds.将大数组放入较小数组的转换存在一个小问题,导致索引 go 超出范围。 I only checked this on pen and paper when I should've put it in the actual code, which is why I didn't notice it.当我应该把它放在实际代码中时,我只在笔和纸上检查了它,这就是我没有注意到它的原因。 Since he didn't post it as an answer, I'm doing so on his behalf.由于他没有将其发布为答案,因此我代表他这样做。

The int gridNew[NNew*NNew]; int gridNew[NNew*NNew]; bit was kind of a red herring, but I appreciate the lesson and will take that into account when coding in C++ in the future.有点像红鲱鱼,但我很欣赏这个教训,并且将来在 C++ 中编码时会考虑到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM