-3

I am writing a snake game and I got a stack overflow in int main() I don't know how to fix it. and I don't really know how to make heap variables :P. The error reads Severity Code Description Project File Line Suppression State Warning C6262 Function uses '17444' bytes of stack: exceeds /analyze:stacksize '16384'. Consider moving some data to heap.

Here is my main:

int main()
{
    vector<point> snek;
    mt19937 mt_rand(time(0));
    snek.push_back({ 10,10 });
    snek.push_back({ 10,9 });
    snek.push_back({ 10,8 });
    snek.push_back({ 10,7 });
    int highscore = 0, score;
    bool tutorial = false;
    bool p = false;
    char move = 'w';
    char sure = 'f';
    string board[21][21];
    int direction = 2;
    point apple;
    apple.x = (mt_rand() % 19) + 1;
    apple.y = (mt_rand() % 19) + 1;
    for (int i = 0; i < 20; i++)
    {
        for (int j = 0; j < 20; j++)
        {
            board[i][j] = "  ";
        }
    }
    bool loss = false;
    while (true)
    {
        score = snek.size() - 4;
        bool  appleEaten = false;
        if (snek[0].x == 0)
            loss = true;
        if (snek[0].x == 20)
            loss = true;
        if (snek[0].y == 0)
            loss = true;
        if (snek[0].y == 20)
            loss = true;
        if (loss)
        {
            system("CLS");
            if (score > highscore)
            {
                highscore = score;
            }
            cout << "You lost with a score of " << snek.size() - 4 << endl;
            cout << "Your highscore for this session is " << highscore << endl;
            cout << "Press any key to play again" << endl;
            cout << "Press RMB to quit" << endl;
            while (true)
            {
                if (GetAsyncKeyState(VK_RBUTTON))
                {
                    system("CLS");
                    cout << "Are you sure you want to quit? Your highscore for this session will be reset" << endl;
                    cout << "Press Q to quit and P to play again" << endl;
                    sure = _getch();
                    if (sure == 'q' || sure == 'Q')
                    {
                        _Exit(0);
                    }
                    if (sure == 'p' || sure == 'P')
                    {
                        p = true;
                    }
                }
                if (_kbhit() || p)
                {
                    for (int i = 0; i < 20; i++)
                    {
                        for (int j = 0; j < 20; j++)
                        {
                            board[i][j] = "  ";
                        }
                    }
                    snek.clear();
                    snek.push_back({ 10,10 });
                    snek.push_back({ 10,9 });
                    snek.push_back({ 10,8 });
                    snek.push_back({ 10,7 });
                    loss = false;
                    p = false;
                    break;
                }
            }
        }
        Sleep(10);
        if (_kbhit())
        {
            move = _getch();
        }
        switch (move)
        {
        case 'w':
            loss = goTo({ (snek[0].x - 1),snek[0].y }, snek);
            Sleep(10);
            break;
        case 'a':
            loss = goTo({ snek[0].x ,(snek[0].y - 1) }, snek);
            Sleep(10);
            break;
        case 's':
            loss = goTo({ (snek[0].x + 1),snek[0].y }, snek);
            Sleep(10);
            break;
        case'd':
            loss = goTo({ snek[0].x ,(snek[0].y + 1) }, snek);
            Sleep(10);
            break;
        }
        board[apple.x][apple.y] = " 0";
        for (int k = 0; k < snek.size() - 1; k++)
        {
            board[snek[k].x][snek[k].y] = " *";
        }
        board[snek[snek.size() - 1].x][snek[snek.size() - 1].y] = "  ";
        if (apple.x == snek[0].x && apple.y == snek[0].y)
        {
            snek.push_back({ snek[snek.size() - 1].x + 1,snek[snek.size() - 1].y });
            appleEaten = true;
        }
        if (appleEaten)
        {
            makeFood(apple, snek);
        }
        for (int i = 0; i < 20; i++)
        {
            board[0][i] = "--";
            board[20][i] = "--";
        }
        for (int i = 0; i < 20; i++)
        {
            board[i][0] = '|';
            board[i][20] = '|';
        }
        if (!tutorial)
        {
            cout << "You are a snake." << endl;
            cout << "Your body looks like this" << endl;
            cout << "*****" << endl;
            cout << "Move with WASD" << endl;
            cout << "If you eat the apples, which look like this " << endl << "0" << endl;
            cout << "You get bigger. If you try to eat yourself or run into walls, you lose" << endl;
            cout << "Click RMB to begin";
            while (true)
            {
                if (GetAsyncKeyState(VK_RBUTTON))
                {
                    system("CLS");
                    tutorial = true;
                    break;
                }
            }
        }
        system("CLS");
        for (int i = 0; i < 21; i++)
        {
            for (int j = 0; j < 21; j++)
            {
                cout << board[i][j];
            }
            cout << endl;
        }
        cout << "Score: " << score;
    }
}
mch
  • 9,424
  • 2
  • 28
  • 42
  • 6
    Please try to minimize the code until the error disappears. Then add back the last bit, and try to remove some other bits until the problem disappears. Once you have the most minimal program possible that replicates the problem you have a [mcve] that you can show us. And it will also make it much easier to *debug* yourself (for example by stepping through statement by statement in an actual debugger). – Some programmer dude Feb 13 '20 at 11:35
  • @Someprogrammerdude ok let me try – Polar Bear Feb 13 '20 at 12:19

2 Answers2

3

I am not sure but string board[21][21]; line is likely root cause of stack overflow. As far as i know std::string stores static array whose size is 15-20 bytes ( size depends on compiler and unspecified by standard ) at stack due to short string optimization.

If it is root cause then one option is allocating data on heap rather than stack, so just change the line

string board[21][21];

to

std::vector<std::vector<std::string>> board { 21 , std::vector<std::string>{ 21 } };
calynr
  • 1,264
  • 1
  • 11
  • 23
  • The short-string optimization shouldn't really matter (unless one indexes the string out of bounds, i.e. when the index is equal to or larger than the string size). The much more likely problem is just out of bounds indexing. Of the strings, or of the arrays. – Some programmer dude Feb 13 '20 at 11:48
  • And as it seems that the OP is only assigning to the strings, or printing them, then any possible short-string optimization is unrelated. So out of bounds of the arrays themselves looks like the likely candidate. And just exchanging the array or arrays with a vector of vector won't by itself solve that. – Some programmer dude Feb 13 '20 at 11:50
  • It could be but compiler complains too much allocation on stack rather than out-bounded index. We can't be exact because @Polar Bear didn't provide a minimal reproducible example :) – calynr Feb 13 '20 at 11:50
  • 1
    `sizeof(std::string)` is usually 32 bytes, at least in gcc in clang, which makes `sizeof(std::string[21][21])` 14112 bytes, which takes the vest majority of the stack, as the error message suggests. – Kaldrr Feb 13 '20 at 12:04
  • If I made the code ``` char board[21][21]``` would that work? – Polar Bear Feb 13 '20 at 12:18
  • @Someprogrammerdude I don't think OP actually has any runtime error or if they have they are not clear about it. The message they are mentioning is just a warning about large stack frames from the compiler. I think they mislabeled that as a "stack overflow". – walnut Feb 13 '20 at 12:21
  • @PolarBear Simply no, also that also means 21 character arrays whose capacity is 21. It is better for you to read tutorial about what char arrays and std::string. – calynr Feb 13 '20 at 12:24
  • 1
    @arnes In general the SSO doesn't need to increase the size of the `std::string` object. A `std::string` needs to store a pointer to allocated memory, a capacity for that memory and a size for the string anyway, which will already make it 24 bytes if implemented in the straight-forward way. SSO usually reuses some of these bytes in a clever way. – walnut Feb 13 '20 at 12:24
  • @walnut so could we remove from the post **due to short string optimization** part ? – calynr Feb 13 '20 at 12:36
  • @arnes Yes, I would remove it, because the statement is pretty much still true without SSO and "15-20 bytes" doesn't seem like a good range. As indicated by the comments "24-32 bytes" seems to be much more common. It also doesn't really depend so much on the compiler as the standard library. For example it is 24 bytes for libc++ and 32 bytes for libstdc++, both of which can be used with Clang. – walnut Feb 13 '20 at 13:11
  • @arnes Ok? I am aware, but it takes up less space and does the same thing, apart from me having to change everything to one character and the board being rectangular but I don't care about that. – Polar Bear Feb 13 '20 at 13:13
  • @walnut if int main() takes up more stack space than it should, is that not a stack overflow? – Polar Bear Feb 13 '20 at 13:14
  • @PolarBear A stack overflow is when the stack taken up (by the whole program) is larger than the stack limit that the operating system allows the program to use. That is a runtime property and can be changed, e.g. with the `ulimit` command on Linux. The message you are getting is a compiler warning which is only meant to reduce the likelihood of a stack overflow at runtime by indicating to you functions with unusually large stack usage. – walnut Feb 13 '20 at 13:18
  • @PolarBear `17444` bytes (as indicated by the warning message) is still less than typical stack limits, so that in only one function that is not recursively called is not a problem. If your program crashes, there is a another reason. – walnut Feb 13 '20 at 13:20
  • @PolarBear If your board only cares about one character at each cell, then you shouldn't have used `std::string` in the first place. In any case, you should, IMO, still prefer `std::vector` over built-in arrays, or in some cases `std::array`, because built-in arrays have some unintuitive behavior in some cases and it is easier to make mistakes with them. – walnut Feb 13 '20 at 13:22
  • @Kaldrr It is 32 bytes for libstdc++ and 24 bytes for libc++. Clang can use both, so you probably tested clang with libstdc++, instead of libc++. – walnut Feb 13 '20 at 13:25
  • @walnut I used string to make everything 2 characters long so the board is square but I could do ``` for (int i = 0; i < 21; i++) { for (int j = 0; j < 21; j++) { cout <<' ' < – Polar Bear Feb 13 '20 at 14:46
-1
string board[21][21];

Mostly uses your stack. You can define it as global variable than i hope you will have enough stack for your program.

idris
  • 488
  • 3
  • 6
  • Ok let me try ill tell you if it worked – Polar Bear Feb 13 '20 at 12:11
  • Oh god thats laggy – Polar Bear Feb 13 '20 at 12:12
  • [Global variables should be avoided](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-global). See also [this question](https://stackoverflow.com/questions/484635/are-global-variables-bad). The array can be allocated dynamically using `std::vector` or `std::unique_ptr` instead. – walnut Feb 13 '20 at 13:31