Переполнение стека

Это игра морской бой.
Раз в n-ное количество генераций игрового поля с расстановкой кораблей на нем происходит переполнение стека.
Ссылается на функцию place, строки 116-118 либо 142-144 (всегда по разному + в зависимости от угла поворота корабля).
Предположительно происходит из за того, что в какой то момент генерации поле переполняется и оставшиеся корабли не помещаются: пробовал убрать несколько кораблей - переполнения стека не происходило, так же пробовал увеличить по размеру игровое поле - переполнения стека так же не происходило, однако это не отвечает заданию и нужно все корабли разместить на поле размером именно 10х10.
Ожидалось, что все будет работать как запланировано и генерация будет всегда работать нормально, но в итоге периодически приводит к крашу программы.

// Sea Battle.cpp : Этот файл содержит функцию "main". Здесь начинается и заканчивается выполнение программы.
//
#include <iostream>
#include <windows.h>
#include <stdlib.h>

using namespace std;

struct ship
{
    short int size;
    bool angle; //false - горизонтальный, true - вертикальный
};

ship b; //battleship
ship c1; //cruiser 1
ship c2; //cruiser 2
ship d1; //destroyer 1
ship d2; //destroyer 2
ship d3; //destroyer 3
ship tp1; //topedo boat 1
ship tp2; //topedo boat 2
ship tp3; //topedo boat 3
ship tp4; //topedo boat 4

bool mcif(ship s, int x, int y) //Main Cell in Field?
{
    if (s.angle == 0)
    {
        if (x >= 0 && x <= 9 - s.size && y >= 0 && y <= 9)return true;
        else return false;
    }
    else
    {
        if (x >= 0 && x <= 9 && y >= 0 && y <= 9 - s.size)return true;
        else return false;
    }
}

bool sdc(char field[10][10], ship s, int x, int y) //Ships Don't Cross?
{
    int count = 0, i = 0;

    if (s.angle == 0)
    {
        for (i; i <= s.size; i++)
        {
            if (field[y][x + i] == '0')count++;
            else return false;;
        }
        if (count == i)return true;
        else return false;
    }

    if (s.angle == 1)
    {
        for (i; i <= s.size; i++)
        {
            if (field[y + i][x] == '0')count++;
            else return false;
        }
        if (count == i)return true;
        else return false;
    }
}

bool cdc(char field[10][10], int x, int y) //Cell Don't Cross?
{
    if (field[x][y] == '0')return true;
    else return false;
}

bool cif(int x, int y) //Cell in Field?
{
    if (x >= 0 && x <= 9 && y >= 0 && y <= 9)return true;
    else return false;
}

void Ships_Generation()
{
    //battleship
    b.size = 4;
    b.angle = rand() % (2 - 0) + 0;
    //cruiser 1
    c1.size = 3;
    c1.angle = rand() % (2 - 0) + 0;
    //cruiser 2
    c2.size = 3;
    c2.angle = rand() % (2 - 0) + 0;
    //destroyer 1
    d1.size = 2;
    d1.angle = rand() % (2 - 0) + 0;
    //destroyer 2
    d2.size = 2;
    d2.angle = rand() % (2 - 0) + 0;
    //destroyer 3
    d3.size = 2;
    d3.angle = rand() % (2 - 0) + 0;
    //torpedo boat 1
    tp1.size = 1;
    tp1.angle = rand() % (2 - 0) + 0;
    //torpedo boat 2
    tp2.size = 1;
    tp2.angle = rand() % (2 - 0) + 0;
    //torpedo boat 3
    tp3.size = 1;
    tp3.angle = rand() % (2 - 0) + 0;
    //torpedo boat 4
    tp4.size = 1;
    tp4.angle = rand() % (2 - 0) + 0;
}

void place(char field[10][10], ship s)
{
    if (s.angle == 0)
    {
        int x = rand() % (10 - s.size); //столбец
        int y = rand() % 10; //столбец


        if (mcif(s, x, y) && sdc(field, s, x, y))
        {
            for (int i = 0; i < s.size + 2; i++)
            {
                int y1 = y - 1;
                int y2 = y;
                int y3 = y + 1;
                int x1 = x - 1 + i;
                if (cif(y1, x1) && cdc(field, y1, x1))field[y1][x1] = '-';
                if (cif(y2, x1) && cdc(field, y2, x1))field[y2][x1] = '-';
                if (cif(y3, x1) && cdc(field, y3, x1))field[y3][x1] = '-';
            }
            for (int i = 0; i < s.size; i++)
            {
                field[y][x + i] = 'X';
            }
        }
        else place(field, s);
    }

    if (s.angle == 1)
    {
        int x = rand() % 10; //строка
        int y = rand() % (10 - s.size); //столбец


        if (mcif(s, x, y) && sdc(field, s, x, y))
        {
            for (int i = 0; i < s.size + 2; i++)
            {
                int y1 = y - 1 + i;
                int x1 = x - 1;
                int x2 = x;
                int x3 = x + 1;
                if (cif(y1, x1) && cdc(field, y1, x1))field[y1][x1] = '-';
                if (cif(y1, x2) && cdc(field, y1, x2))field[y1][x2] = '-';
                if (cif(y1, x3) && cdc(field, y1, x3))field[y1][x3] = '-';
            }
            for (int i = 0; i < s.size; i++)
            {
                field[y + i][x] = 'X';
            }
        }
        else place(field, s);
    }
}

void Field_Generation(char field[10][10])
{
    Ships_Generation();

    place(field, b);
    place(field, c1);
    place(field, c2);
    place(field, d1);
    place(field, d2);
    place(field, d3);
    place(field, tp1);
    place(field, tp2);
    place(field, tp3);
    place(field, tp4);
}

int main()
{
    system("chcp 1251 > NUL");
    srand((unsigned int)time(NULL));
    char Field[10][10]{};

    cout << "---Морской Бой---" << endl;
    cout << R"(
    Начать игру (P)
    Настройки (S)
    Выйти (E)
)";
    char ctrl = ' ';
    cin >> ctrl;
    if (ctrl == 'E' || ctrl == 'e')
    {
        cout << "Вы уверены, что хотите выйти из игры? (Y/N)" << endl; cin >> ctrl;
        if (ctrl == 'Y' || ctrl == 'y')
        {
            cout << "До скорых встреч!" << endl;
            Sleep(1500);
        }
        else exit(1);
    }
    else if (ctrl == 'P' || ctrl == 'p')
    {
        do
        {
            system("cls");


            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    Field[i][j] = '0';
                }
            }
            Field_Generation(Field);
            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    //cout << "|" << Field[i][j] << "| ";
                    cout << Field[i][j] << " ";
                }
                cout << endl;
                //cout << "|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|" << endl;
            }
            cout << "\nИграть заново? "; cin >> ctrl;
        } while (ctrl == 'R' || ctrl == 'r');
    }
}

Также Visual Studio выдает предупреждение: C8386: Переполнение буфера при записи в "field[y1]" (строка 159).
Может ли это быть связано с переполнением стека?


Ответы (1 шт):

Автор решения: AvidCoder

В функции place, если выполняется одно из условий

s.angle == 0 или s.angle == 1

, но не выполняется условие

mcif(s, x, y) && sdc(field, s, x, y)

, вы вызываете place(field, s), что равносильно изначальному вызову, так как при проверке переменные field и s не изменяются.

Это приводит к бесконечной рекурсии.


C8386: Переполнение буфера при записи в "field[y1]" предупреждает о возможной записи за пределы массива. Стоит перепроверить правильность ограничений.

→ Ссылка