Access violation writing location 0xFDFDFE05

0

Mam problem: Unhandled exception at 0x01212FEB in Snake.exe: 0xC0000005: Access violation writing location 0xFDFDFE05. Testujac resetowanie pozycji Snake'a, debugger wyrzuca mi ten blad, gdy poruszajac sie po osi Y trafi na gorna badz dolna krawedz. Z osia X jest prawie ok, prawie, bo prawidlowo przerzuca, ale w momencie dojscia do sciany, przy iteracji, podczas, ktorej Snake powininen pokazac sie po drugiej stronie - nic sie nie dzieje, dopiero w nastepnej iteracji, pojawia sie w miejscu, w ktorym powinien. Kod na os Y wydawaloby sie mam logicznie zmodyfikowany i nie moge dosc, dlaczego tak sie dzieje. Wrzucam caly kod, na wypadek gdyby ktos chcial odpalic go u siebie, ale problem podejrzewam znajduje sie w funkacjach DefineFields() i MoveAndControl().
Z gory dzieki za pomoc.

#pragma once

struct BoardProperties
{
	int Width;
	int Height;
};
 
#include <iostream>
#include <conio.h>
#include <time.h>
#include <Windows.h>
#include "Struct.h"

void Intro();
void ConsoleSettings();												//rozmiary boardu
void GameSettings();												//tempo i definicja klawiszy
//void DrawBoard(char **Board, struct BoardProperties Size);			//czysci ekran i rysuje board o podanych rozmiarach
void DefineFields(struct BoardProperties Size);
void InputError(int &Size);											//jesli podano wartosci spoza skali, pomysl o walidacji inputow
void KeyboardError(int &Key);										//klawisze kursorow skladaja sie z dwoch liczb(?)
void MoveAndControl(int &SnakePosX, int &SnakePosY, char **Board, struct BoardProperties Size);

int main()
{
	Intro();
	GameSettings();
	ConsoleSettings();
	//DefineFields(Width, Height);
	//DrawBoard(ConsoleSize);
	
	return 0;
}

void Intro()
{
	std::cout << "***** SNAKE *****";
	std::cout << std::endl;
	return;
}

void ConsoleSettings()
{
	int Width;
	int Height;
	
	std::cout << "Podaj szerokosc pola w zakresie od 5 do 40: ";
	std::cin >> Width;
	
	if (Width < 5 || Width > 40)
	{
		InputError(Width);
	}
	std::cout << "Podaj wysokosc pola w zakresie od 5 do 40: ";
	std::cin >> Height;

	if (Height < 5 || Height > 40)
	{
		InputError(Height);
	}

	BoardProperties ConsoleSize;
	ConsoleSize.Width = Width;
	ConsoleSize.Height = Height;

	//----------------------------------------------------------------------------------------------
	std::cout << "ConsoleSize.Width = " << ConsoleSize.Width << std::endl;					//Test struktury
	std::cout << "ConsoleSize.Height = " << ConsoleSize.Height << std::endl;
	//----------------------------------------------------------------------------------------------

	DefineFields(ConsoleSize);
	//DrawBoard(Board, ConsoleSize);

	return;
}

void GameSettings()
{
	int Tempo;
	int Up, Down, Left, Right;

	std::cout << "Podaj szybkosc w zakresie od 1 do 10: ";
	std::cin >> Tempo;

	if (Tempo < 1)
	{
		Tempo = 1;
	}
	if (Tempo > 10)
	{
		Tempo = 10;
	}

	std::cout << "Wybierz klawisze, ktorymi chcesz grac: \n";
	std::cout << "GORA\n";
	Up = _getch();
	KeyboardError(Up);

	std::cout << "DOL\n";
	Down = _getch();
	KeyboardError(Down);

	std::cout << "LEWO\n";
	Left = _getch();
	KeyboardError(Left);
	
	std::cout << "PRAWO\n";
	Right = _getch();
	KeyboardError(Right);
}

void InputError(int &Size)
{
	std::cout << "Podano liczbe spoza zakresu. Sprobuj ponownie: ";
	std::cin >> Size;
	if (Size < 5 || Size > 40)
	{
		Size = 20;
	}
	return;
}

void KeyboardError(int &Key)
{
	if (Key == 224)
	{
		Key += _getch();
	}
	if (Key == 0)
	{
		Key -= _getch();
	}
}

void DefineFields(struct BoardProperties Size)
{
	char **Board;
	Board = new char *[Size.Height];
	for (int i = 0; i < Size.Height; i++)
	{
		Board[i] = new char[Size.Width];
	}

	for (int j = 0; j < Size.Height; j++)
	{
		for (int k = 0; k < Size.Width; k++)
		{
			Board[j][k] = 'e';
		}																				//e - Empty field
	}

	//------------------------------------------------------------------------------------------------
	/*for (int i = 0; i < Size.Height; i++)
	{
	for (int j = 0; j < Size.Width; j++)					//test tablicy
	{
	std::cout << Board[j][i];
	}
	}*/
	//------------------------------------------------------------------------------------------------

	int SnakePosX, SnakePosY;
	int FoodPosX, FoodPosY;

	srand(time(NULL));

	SnakePosX = rand() % Size.Width;
	SnakePosY = rand() % Size.Height;

	Board[SnakePosY][SnakePosX] = 's';						//s - Snake on field

	do
	{
		FoodPosX = rand() % Size.Width;
		FoodPosY = rand() % Size.Height;
	} while (Board[FoodPosY][FoodPosX] != 'e');
	Board[FoodPosY][FoodPosX] = 'f';						//f- Food on field
	
	for (;;)
	{
		Sleep(500);

		system("cls");
		// GORNA RAMA------------------------------------------------------------------------------------
		for (int i = 0; i <= Size.Width; i++)
		{
			std::cout << "--";
		}
		std::cout << std::endl;

		// BOCZNE RAMY-----------------------------------------------------------------------------------
		for (int j = 0; j < Size.Height; j++)
		{
			std::cout << "|";

			for (int k = 0; k < Size.Width; k++)
			{
				if (Board[j][k] == 'e')
				{
					std::cout << "  ";
				}
				if (Board[j][k] == 's')
				{
					std::cout << " o";
				}
				if (Board[j][k] == 'f')
				{
					std::cout << " x";
				}
			}
			std::cout << "|" <<std::endl;
		}

		// DOLNA RAMA-------------------------------------------------------------------------------------
		for (int l = 0; l <= Size.Width; l++)
		{
			std::cout << "--";
		}
		std::cout << std::endl;

		MoveAndControl(SnakePosX, SnakePosY, Board, Size);
	}

	return;
}

void MoveAndControl(int &SnakePosX, int &SnakePosY, char **Board, struct BoardProperties Size)
{
	SnakePosY--;
	Board[SnakePosY][SnakePosX] = 's';

	if (SnakePosX == Size.Width)
	{
		SnakePosX = 0;
	}

	if (SnakePosX == -1)
	{
		SnakePosX = Size.Width - 1;
	}

	if (SnakePosY == Size.Height)
	{
		SnakePosY = 0;
	}

	if (SnakePosY == -1)
	{
		SnakePosY = Size.Height - 1;
	}

	std::cout << "Size.Width = " << Size.Width << std::endl;
	std::cout << "Size.Height = " << Size.Height << std::endl;

	return;
}

 
0

o_O

SnakePosY--;
Board[SnakePosY][SnakePosX] = 's';

A jak SnakePosY był 0 przy wejściu do funkcji to co? To zrobisz z niego -1 a potem walisz po tablicy z indeksem -1? Szczególnie ze sam masz tam warunek

    if (SnakePosY == Size.Height)
    {
        SnakePosY = 0;
    }

Więc nawet wiadomo kiedy taką akcje zrobisz. Ba, u ciebie w ogóle jakiś geniusz destrukcji sie objawia bo sam masz tam nawet warunek:

    if (SnakePosY == -1)
    {
        SnakePosY = Size.Height - 1;
    }

mimo że powyzej tego kodu robisz Board[SnakePosY][SnakePosX] = 's'; Czyli ty wiesz ze ta zmienna moze być -1 a mimo to wesoło indeksujesz nią tablice. o_O
No i oczywiśćie dla X mamy dokładnie to samo:

    if (SnakePosX == -1)
    {
        SnakePosX = Size.Width - 1;
    }

że może być -1. Brak mi słów. Ty rozumiesz ze Board[-1][-1] to jest słabe odwołanie?

0

Kurczę, a mógłbyś mi to trochę bardziej objaśnić? Bo dla Ciebie to jakiś trywialny błąd, ale ja nie do końca łapię...

Przeanalizuję to sobie, dzięki wielkie

0

Ale czego nie łapiesz? Tak majstrujesz przy tych swoich zmiennych SnakePosY i SnakePosX że ich wartości w trakcie wykonania linijki Board[SnakePosY][SnakePosX] = 's'; mogą wynosić -1, a to nie jest dobry indeks w twojej tablicy i takie odwołenie wyłazi poza tablicę i wywala program, bo nie wolno ci pisać po pamięci poza twoją tablicą.

0
void MoveAndControl(int &SnakePosX, int &SnakePosY, char **Board, struct BoardProperties Size)
{
	SnakePosY++;

	if (SnakePosX == Size.Width)
	{
		SnakePosX = 1;
	}

	if (SnakePosX == 0)
	{
		SnakePosX = Size.Width;
	}

	if (SnakePosY == Size.Height)
	{
		SnakePosY = 1;
	}

	if (SnakePosY == 0)
	{
		SnakePosY = Size.Height;
	}
	
	Board[SnakePosY][SnakePosX] = 's';
	
	std::cout << "Size.Width = " << Size.Width << std::endl;
	std::cout << "Size.Height = " << Size.Height << std::endl;

	return;
}
 

Czemu dla warunku if (SnakePosX == Size.Width) oraz if (SnakePosY == Size.Height) nie moge dac SnakePosX = 0; i SnakePosY = 0; ?
Rozumiem już o co, Ci chodzi, dla ruchu w lewo i w dol dziala pieknie, dla ruchu w prawo i w gore pojawia sie komorke za sciana, a chcialbym by pojawialo sie zaraz przy niej.
Dzieki wielke, jakby rozumiem juz istote mojej glupoty w tych instrukcjach.

0

A czemu niby nie możesz dać tam 0? Ktoś ci zabrania?

0

Ruch w dol - dociera do krawedzi, po czym wyrzuca blad - snake.exe has stopped working.
Ruch w gore - dociera do drugiego rzedu liczac od gory i wyrzuca Game Over zamiast ziterowac sie jeszcze raz.
Ruch w prawo - prawidlowo. Dociera do konca, po czym Game Over.
Ruch w lewo - dociera do przedostatniego rzedu i wykonuje instrukcje, a nie na ostatnim.

Mógłbyś mi to wyjaśnić?

#include <iostream>
#include <conio.h>
#include <time.h>
#include <Windows.h>
#include "Struct.h"

void Intro();
void ConsoleSettings();												//rozmiary boardu
void GameSettings();												//tempo i definicja klawiszy
//void DrawBoard(char **Board, struct BoardProperties Size);			//czysci ekran i rysuje board o podanych rozmiarach
void DefineFields(struct BoardProperties Size);
void InputError(int &Size);											//jesli podano wartosci spoza skali, pomysl o walidacji inputow
void KeyboardError(int &Key);										//klawisze kursorow skladaja sie z dwoch liczb(?)
void MoveAndControl(int &SnakePosX, int &SnakePosY, char **Board, struct BoardProperties Size);

int main()
{
	Intro();
	GameSettings();
	ConsoleSettings();
	//DefineFields(Width, Height);
	//DrawBoard(ConsoleSize);
	
	return 0;
}

void Intro()
{
	std::cout << "***** SNAKE *****";
	std::cout << std::endl;
	return;
}

void ConsoleSettings()
{
	int Width;
	int Height;
	
	std::cout << "Podaj szerokosc pola w zakresie od 5 do 40: ";
	std::cin >> Width;
	
	if (Width < 5 || Width > 40)
	{
		InputError(Width);
	}
	std::cout << "Podaj wysokosc pola w zakresie od 5 do 40: ";
	std::cin >> Height;

	if (Height < 5 || Height > 40)
	{
		InputError(Height);
	}

	BoardProperties ConsoleSize;
	ConsoleSize.Width = Width;
	ConsoleSize.Height = Height;

	//----------------------------------------------------------------------------------------------
	std::cout << "ConsoleSize.Width = " << ConsoleSize.Width << std::endl;					//Test struktury
	std::cout << "ConsoleSize.Height = " << ConsoleSize.Height << std::endl;
	//----------------------------------------------------------------------------------------------

	DefineFields(ConsoleSize);
	//DrawBoard(Board, ConsoleSize);

	return;
}

void GameSettings()
{
	int Tempo;
	int Up, Down, Left, Right;

	std::cout << "Podaj szybkosc w zakresie od 1 do 10: ";
	std::cin >> Tempo;

	if (Tempo < 1)
	{
		Tempo = 1;
	}
	if (Tempo > 10)
	{
		Tempo = 10;
	}

	std::cout << "Wybierz klawisze, ktorymi chcesz grac: \n";
	std::cout << "GORA\n";
	Up = _getch();
	KeyboardError(Up);

	std::cout << "DOL\n";
	Down = _getch();
	KeyboardError(Down);

	std::cout << "LEWO\n";
	Left = _getch();
	KeyboardError(Left);
	
	std::cout << "PRAWO\n";
	Right = _getch();
	KeyboardError(Right);
}

void InputError(int &Size)
{
	std::cout << "Podano liczbe spoza zakresu. Sprobuj ponownie: ";
	std::cin >> Size;
	if (Size < 5 || Size > 40)
	{
		Size = 20;
	}
	return;
}

void KeyboardError(int &Key)
{
	if (Key == 224)
	{
		Key += _getch();
	}
	if (Key == 0)
	{
		Key -= _getch();
	}
}

void DefineFields(struct BoardProperties Size)
{
	char **Board;
	Board = new char *[Size.Height];
	for (int i = 0; i < Size.Height; i++)
	{
		Board[i] = new char[Size.Width];
	}

	for (int j = 0; j < Size.Height; j++)
	{
		for (int k = 0; k < Size.Width; k++)
		{
			Board[j][k] = 'e';
		}																				//e - Empty field
	}

	//------------------------------------------------------------------------------------------------
	/*for (int i = 0; i < Size.Height; i++)
	{
	for (int j = 0; j < Size.Width; j++)					//test tablicy
	{
	std::cout << Board[j][i];
	}
	}*/
	//------------------------------------------------------------------------------------------------

	int SnakePosX, SnakePosY;
	int FoodPosX, FoodPosY;

	srand(time(NULL));

	SnakePosX = rand() % Size.Width;
	SnakePosY = rand() % Size.Height;

	Board[SnakePosY][SnakePosX] = 's';						//s - Snake on field

	do
	{
		FoodPosX = rand() % Size.Width;
		FoodPosY = rand() % Size.Height;
	} while (Board[FoodPosY][FoodPosX] != 'e');
	Board[FoodPosY][FoodPosX] = 'f';						//f- Food on field
	
	for (;;)
	{
		Sleep(500);

		system("cls");
		// GORNA RAMA------------------------------------------------------------------------------------
		for (int i = 0; i <= Size.Width; i++)
		{
			std::cout << "--";
		}
		std::cout << std::endl;

		// BOCZNE RAMY-----------------------------------------------------------------------------------
		for (int j = 0; j < Size.Height; j++)
		{
			std::cout << "|";

			for (int k = 0; k < Size.Width; k++)
			{
				if (Board[j][k] == 'e')
				{
					std::cout << "$$";
				}
				if (Board[j][k] == 's')
				{
					std::cout << " o";
				}
				if (Board[j][k] == 'f')
				{
					std::cout << " x";
				}
			}
			std::cout << "|" <<std::endl;
		}

		// DOLNA RAMA-------------------------------------------------------------------------------------
		for (int l = 0; l <= Size.Width; l++)
		{
			std::cout << "--";
		}
		std::cout << std::endl;

		//MoveAndControl(SnakePosX, SnakePosY, Board, Size);

		SnakePosY--;
		Board[SnakePosY][SnakePosX] = 's';

		if (SnakePosX == Size.Width)
		{
			std::cout << "GAME OVER" << std::endl;
			break;
		}

		if (SnakePosX == 0)
		{
			std::cout << "GAME OVER" << std::endl;
			break;
		}

		if (SnakePosY == Size.Height)
		{
			std::cout << "GAME OVER" << std::endl;
			break;
		}

		if (SnakePosY == 0)
		{
			std::cout << "GAME OVER" << std::endl;
			break;
		}
	}

	return;
}
 
0

Aż mi słabo jak czytam twoje posty. Weź ty chłopie zrób jak normalny człowiek, odpal debuger, podstaw pare breakpointów z warunkami na sytuacje gdzie się coś wywala. A następnie klikaj program step-by-step i przyglądaj się wartością zmiennych i adresom do których sie odnosisz. Co, mamy to zrobić za ciebie czy jak?
Zresztą ja w tym kodzie nadal widze genialne

        SnakePosY--;
        Board[SnakePosY][SnakePosX] = 's';

Które może wywalić gre już na starcie jak przypadkiem wylosuje ci się PosY = 0 (a przecież może bo reszta z dzielenia może wynosić 0).

Poza tym piszesz ten kod strasznie słabo. Nie operuj na jakichś globalnych stanach i referencjach do zmiennych tylko zwracaj wyniki z funkcji jak normalny człowiek. Bo teraz ogarnianie kiedy i kto zmienia jakąś zmienną to jest ciężki WTF i ty sam ewidentnie się w tym gubisz. Zapamiętaj sobie że funkcja void sugeruje że coś w kodzie jest nie tak. Jedyna funkcja która powinna tu być void to ta rysująca plansze. Wszystkie inne powinny zwracać wyniki a nie ustawiać wartości globalnych pól albo zmieniać wartości zmiennych przekazanych przez referencje.

0
SnakePosY--;
Board[SnakePosY][SnakePosX] = 's';
 

sluzy tylko i wylacznie do testowania, co sie dzieje, gdy waz pojedzie w danym kierunku, nie mam jeszcze zaimplementowanego sterowania, wiec domyslnie na pewno tego nie bedzie. Dzięki wielkie za pomoc.

Nie wiem jak robi normalny czlowiek, pierwszy semestr informatyki, niemalze na kazdych cwiczeniach mam zmienne globalne etc etc. A snake'a po prostu robie dodatkowo po godzinach.

1 użytkowników online, w tym zalogowanych: 0, gości: 1