Переполнение стека
Это игра морской бой.
Раз в 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 шт):
В функции place
, если выполняется одно из условий
s.angle == 0
или s.angle == 1
, но не выполняется условие
mcif(s, x, y) && sdc(field, s, x, y)
, вы вызываете place(field, s)
, что равносильно изначальному вызову, так как при проверке переменные field
и s
не изменяются.
Это приводит к бесконечной рекурсии.
C8386: Переполнение буфера при записи в "field[y1]"
предупреждает о возможной записи за пределы массива. Стоит перепроверить правильность ограничений.