简体   繁体   中英

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.

I'm trying to implement the box counting method for a randomly generated 2D cluster in a lattice that's 54x54.

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. 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.

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. 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). However, when I run it, the box size goes all the way to 1/37 and gives me a "stack smashing detected" error.

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.

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. 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. 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. 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. It is indeed the case, which is likely the origin of the problem.

EDIT #2: It was indeed the origin of the problem. 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. 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.

  1. int gridNew[NNew*NNew]; You should know that this is not valid according to C++ standard, only the GCC compiler made it work. In C++ you always have to know the size of the fixed arrays in compile time. 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.

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

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.

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. 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.

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. 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. 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]; 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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