1

Тема: Помилка "Читання пам'яті неможливо"

Доброго вечора! Вирішив написати прості консольні Хрестики-нулики, зіткнувся з проблемою.

вибиває ось цю помилку

http://i.imgur.com/zkf2brz.png

Помилка виникає, коли я намагаюся зациклити функцію, дописавши в кінці - bot();

Ця функція
void bot() {
    int arr02[] = { 8,10,12,22,24,26,36,38,40 }; // Числа в масиві - це індекси чисел 1,2,3,4,5,6,7,8,9 в масиві arr[]
    srand((unsigned)time(NULL));
     int index = rand() % 9; // випадкове число 
     
         if (arr[arr02[index]] != 'X' && 'O') { 
             arr[arr02[index]] = 'O';
         }
         else {
             bot();     
         }
     }

Суть в тому, що бот виставляє "нулики" в випадкову клітинку.
Я роблю, спочатку перевірку, чи клітинка не занята вже "нулем" або "хрестиком", якщо так: то функція повинна виконуватися заново, якщо ні: то в клітинку ставиться нулик .

Весь код програми
#include <iostream>
#include<locale.h> 
#include <time.h>
using namespace std;

// Масив дошки
char arr[] ={
    '-','-','-','-','-','-','-',
    '|','1','|','2','|','3','|',
    '-','-','-','-','-','-','-',
    '|','4','|','5','|','6','|',
    '-','-','-','-','-','-','-',
    '|','7','|','8','|','9','|',
    '-','-','-','-','-','-','-',
};

// Прототипи функцій
void vubir();
void doska();
void bot();

// Виклики всіх функцій
void main() {
    setlocale(LC_ALL, "RUS");

    doska();

    cout << "Ви граэте за хрестики. Нажмiть: 1,2,3,4,5,6,7,8 або 9, " << endl;
    
        
        vubir();
        bot();
        doska();
        //canInput();
        cout << "Нажмiть: 1,2,3,4,5,6,7,8 або 9, " << endl;
        
        vubir();
        bot();
        doska();
        //canInput();
        cout << "Нажмiть: 1,2,3,4,5,6,7,8 або 9, " << endl;
        
        vubir();
        bot();
        doska();
        //canInput();
        cout << "Нажмiть: 1,2,3,4,5,6,7,8 або 9, " << endl;
        
        vubir();
        bot();
        doska();
        //canInput();
        cout << "Нажмiть: 1,2,3,4,5,6,7,8 або 9, " << endl;
        
        vubir();
        bot();
        doska();
        //canInput();
        cout << "Нажмiть: 1,2,3,4,5,6,7,8 або 9, " << endl;
    
        


    system("pause");
    
}

// Малюємо дошку.
void doska() {
    for (int a = 0;a < 7;a++)
        cout << arr[a];
    cout << endl;
    for (int a = 7;a < 14;a++)
        cout << arr[a];
    cout << endl;
    for (int a = 14; a<21; a++)
        cout << arr[a];
    cout << endl;
    for (int a = 21;a<28;a++)
        cout << arr[a];
    cout << endl;
    for (int a = 28; a<35; a++)
        cout << arr[a];
    cout << endl;
    for (int a = 35;a<42;a++)
        cout << arr[a];
    cout << endl;
    for (int a = 42;a<49;a++)
        cout << arr[a];
    cout << endl;
}

// Бот - противник.
void bot() {
    int arr02[] = { 8,10,12,22,24,26,36,38,40 }; // Числа в масиві - це індекси чисел 1,2,3,4,5,6,7,8,9 в масиві arr[]
    srand((unsigned)time(NULL));
     int index = rand() % 9; // випадкове число 
     
         if (arr[arr02[index]] != 'X' && 'O') {
             arr[arr02[index]] = 'O';
         }
         else {
             bot();     
         }
     }

// Вибір гравцем де поставити хрестик.
void vubir() {
    int step;

    cin >> step;
    switch (step) {
    case 1:
        arr[8] = char('X');
        doska();
        break;
    case 2:
        arr[10] = char('X');
        doska();
        break;
    case 3:
        arr[12] = char('X');
        doska();
        break;
    case 4:
        arr[22] = char('X');
        doska();
        break;
    case 5:
        arr[24] = char('X');
        doska();
        break;
    case 6:
        arr[26] = char('X');
        doska();
        break;
    case 7:
        arr[36] = char('X');
        doska();
        break;
    case 8:
        arr[38] = char('X');
        doska();
        break;
    case 9:
        arr[40] = char('X');
        doska();
        break;
    }
}

2

Re: Помилка "Читання пам'яті неможливо"

Навіть не знаю, з чого починати, тут прекрасно все...
Конкретно ця помилка виникає від того, що раніше запущена програма не була завершена (перезапустіть Visual Studio і припиніть свою програму в диспетчері задач, якщо ще лишилася).
Але це не причина. Причина в тому, що у вас нескінчений цикл. Якби VS був трохи тупішим, то програма б валилася одразу після запуску із криком про переповнення стеку, але він розумний, і цю абсолютно непотрібну, навіть шкідливу рекурсію перетворює на цикл.
А цикл нескінчений, бо весь час перевіряє одну й ту саму умову. Ви не вмієте складати логічні вирази, через це друга половина складного виразу в рядку 99 фактично ігнорується, але справа навіть не у цьому. Можливо, справа у тому, що srand виставляє значення випадкової величини на свій параметр - у вашому випадку значення секунди. А воно не змінюється від переходу на наступну ітерацію.

Отже, перенесіть srand в main і викликайте його там рівно один раз, на початку роботи програми. І зробіть цикл циклом(for або while), а не "зациклюванням". Втім, не факт, що програма запрацює - я навіть дивитися на ваші масиви не хочу.

Подякували: Valsoray, leofun012

3

Re: Помилка "Читання пам'яті неможливо"

koala написав:

Втім, не факт, що програма запрацює - я навіть дивитися на ваші масиви не хочу.

Не всі можуть зразу почати писати програми правильно і зрозуміло, мабуть. Це по факту, моя перша спроба, щось більш менш толкове написати самому.
Дякую за допомогу.

4

Re: Помилка "Читання пам'яті неможливо"

Дам вам ще пару порад:
- DRY - don't repeat yourself. Не повторюйтесь. Наприклад, у doska() можна додати ще один зовнішній цикл і зібрати все до купи:

for(int j=0;j<7;++j) {
    for (int a = j*7;a < (j+1)*7;a++)
        cout << arr[a];
    cout << endl;
}

Втім, конкретно тут це не має значення, бо
- відділяйте суть від представлення. По суті у вас поле 3х3, а в 7х7 воно перетворюється лише для виводу в функції doska - то проголошуйте його масивом масивів [3][3], а в doska вже виводьте всі ці ваші рисочки. Так, воно може видатися не дуже очевидним - зате воно буде таким в одному місці, а не в десятьох по всій програмі. Зокрема, стане очевидним, що не потрібен switch/case у vubir() - хоча він, насправді, і так не потрібен.

Подякували: Valsoray, leofun012

5

Re: Помилка "Читання пам'яті неможливо"

Теж колись робив цю гру в процедурній парадигмі.

/*
 * Tic-Tac-Toe
 * This is simple console game Tic-Tac-Toe
 *
 * Author: 
 */
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <Windows.h>

using namespace std;

const char X = 'X';
const char O = 'O';
const char EMPTY = ' ';
const char TIE = 'T';
const char NO_ONE = 'N';

void instructions();//displays the rules
char askYesNo(string question);//Takes question and return answer "yes" or "no"
int askNumber(string question, int hight, int low = 0);//asks a number of ranges and returns the number of ranges of low-hight
char humanPiece();//determine which figures will play user
char opponent(char piece); //knowing what figures will play the user and determines the shape computer figure
void displayBoard(const vector<char>& board);//displays field
char winner(const vector<char>& board);//determine who is winner, returns O, X, T (no winner) or N (two players have a chance to win)
bool isLegal(int move, const vector<char>& board);//determines whether the move made by the rules
int humanMove(const vector<char>& board, char human);//determine user's move. Takes field and figure of user, returns user's move
int computerMove(vector<char> board, char computer);//determine computer's move. Takes field and figure of computer, returns computer's move
void announceWinner(char winner, char computer, char human);//congratulates the winner. Takes winner's side, figure and computer's figure

int main()
{
    char playAgain = 'n';
    do
    {
        int move;
        const int NUM_SQUARES = 9;
        vector<char> board(NUM_SQUARES, EMPTY);
        instructions();
        char human = humanPiece();
        char computer = opponent(human);
        char turn = X;
        displayBoard(board);
        while (winner(board) == NO_ONE)
        {
            if (turn == human)
            {
                move = humanMove(board, human);
                board[move] = human;
            }
            else
            {
                move = computerMove(board, computer);
                board[move] = computer;
            }
            displayBoard(board);
            turn = opponent(turn);
        }
        announceWinner(winner(board), computer, human);
        //play again
        cout << "Play again? (y/n) - ";
        cin >> playAgain;
        if (playAgain == 'y')
        {
            system("cls");
        }
        else
            break;
    } while (playAgain == 'y');
    if (playAgain == 'n')
    {
        cout << "Goodbye, craven human." << endl;
        return 0;
    }
}

void instructions()
{
    cout << "\t\tWelcome to Tic-Tac-Toe Console Game" << endl;
    cout << "...and you will lose here" << endl;
    cout << "Make your move known by entering a number 0 - 8. The number corresponds to the desired board position, as illustrated:" << endl;
    cout << "\t\t 0 | 1 | 2 " << endl;
    cout << "\t\t-----------" << endl;
    cout << "\t\t 3 | 4 | 5 " << endl;
    cout << "\t\t-----------" << endl;
    cout << "\t\t 6 | 7 | 8 " << endl;
    cout << "Prepare youself, human. The battle is about to begin.\n" << endl;
}

char askYesNo(string question)
{
    char response;
    do
    {
        cout << question << "(y / n) - ";
        cin >> response;
    } while (response != 'y' && response != 'n');
    return response;
}

int askNumber(string question, int hight, int low)
{
    int number;
    do
    {
        cout << question << "(" << low << "..." << hight << ") - ";
        cin >> number;
    } while (number > hight || number < low);
    return number;
}

char humanPiece()
{
    char goFirst = askYesNo("Do you require the first move? ");
    if (goFirst == 'y')
    {
        cout << "Then take the first move. You will need it." << endl;
        return X;
    }
    else
    {
        cout << "Your bravery will be your undoing. I will go first." << endl;
        Sleep(3000);
        return O;
    }
}

char opponent(char piece)
{
    if (piece == X)
        return O;
    else
        return X;
}

void displayBoard(const vector<char>& board)
{
    cout << "\t\t" << " " << board[0] << " | " << board[1] << " | " << board[2]  << endl;
    cout << "\t\t-----------" << endl;
    cout << "\t\t" << " " << board[3] << " | " << board[4] << " | " << board[5] << endl;
    cout << "\t\t-----------" << endl;
    cout << "\t\t" << " " << board[6] << " | " << board[7] << " | " << board[8] << endl;
}

char winner(const vector<char>& board)
{
    //all possible winning fields
    const int WINNING_ROWS[8][3] = { {0, 1, 2},
    {3, 4, 5},
    {6, 7, 8},
    {0, 3, 6},
    {1, 4, 7},
    {2, 5, 8},
    {0, 4, 8},
    {2, 4, 6} };
    const int TOTAL_ROWS = 8;
    //if here is three equal values in some row (and it not equal EMPTY) the winner is defined
    for (int row = 0; row < TOTAL_ROWS; ++row)
    {
        if ((board[WINNING_ROWS[row][0]] != EMPTY) && (board[WINNING_ROWS[row][0]] == board[WINNING_ROWS[row][1]])
            && (board[WINNING_ROWS[row][1]] == board[WINNING_ROWS[row][2]]))
        {
            return board[WINNING_ROWS[row][0]];
        }
    }
    //if winner is not defined verify whether tie (if empty cells left on field)
    if (count(board.begin(), board.end(), EMPTY) == 0)
        return TIE;
    //if winner is not defined but it is not tie, game continue
    return NO_ONE;
}

inline bool isLegal(int move, const vector<char>& board)
{
    return (board[move] == EMPTY);
}

int humanMove(const vector<char>& board, char human)
{
    int move = askNumber("Where will you move?", (board.size() - 1));
    while (!isLegal(move, board))
    {
        cout << "\nThat square is already occupied, foolish human." << endl;
        move = askNumber("Where will you move?", (board.size() - 1));
    }
    cout << "Fine..." << endl;
    Sleep(1000);
    system("cls");
    return move;
}

//strategy for computer moving operation:
//1. if computer can make winning move - do this move
//2. else if human can win in next move - block this move
//3. else occupy best cell (best - center cell, less the best - corner cells and other is worse)
int computerMove(vector<char> board, char computer)
{
    unsigned int move = 0;
    bool found = false;
    //1. if computer can make winning move - do this move
    while (!found && move < board.size())
    {
        if (isLegal(move, board))
        {
            board[move] = computer;
            found = winner(board) == computer;
            board[move] = EMPTY;
        }
        if (!found)
            ++move;
    }
    //2. else if human can win in next move - block this move
    if (!found)
    {
        move = 0;
        char human = opponent(computer);
        while (!found && move < board.size())
        {
            if (isLegal(move, board))
            {
                board[move] = human;
                found = winner(board) == human;
                board[move] = EMPTY;
            }
            if (!found)
            {
                ++move;
            }
        }
    }
    //3. else occupy best cell (best - center cell, less the best - corner cells and other is worse)
    if (!found)
    {
        move = 0;
        unsigned int i = 0;
        const int BEST_MOVES[] = { 4,0,2,6,8,1,3,5,7 };
        //choose optimal free cell
        while (!found && i < board.size())
        {
            move = BEST_MOVES[i];
            if (isLegal(move, board))
            {
                found = true;
            }
            ++i;
        }
    }
    system("cls");
    cout << "I shall take square number " << move << endl;
    return move;
}

void announceWinner(char winner, char computer, char human)
{
    if (winner == computer)
    {
        cout << winner << "'s won!" << endl;
        cout << "As I predicted, human, I am triumphant once more -- proof that computers are superior to humans in all regards." << endl;
    }
    else if (winner == human)
    {
        cout << winner << "'s won!" << endl;
        cout << "No, no! It cannot be! Somehow you tricked me, human." << endl;
        cout << "But never again! I, the computer, so swear it! Get it, motherf***er?" << endl;
    }
    else
    {
        cout << "It's a tie." << endl;
        cout << "You were most lucky, human, and somehow manage to tie me." << endl;
        cout << "Celebrate for this the best you will ever achieve." << endl;
    }
}

6

Re: Помилка "Читання пам'яті неможливо"

        cout << "Play again? (y/n) - ";
        cin >> playAgain;
        if (playAgain == 'y')
        {
            system("cls");
        }

Бачу, я тут не єдиний індус, творімо земляцтво чи що  *JOKINGLY*

Подякували: LoganRoss, koala, /KIT\, leofun014

7

Re: Помилка "Читання пам'яті неможливо"

0xDADA11C7 написав:

Бачу, я тут не єдиний індус, творімо земляцтво чи що  *JOKINGLY*

Давайте. Проводимо референдум і називаємо землі Індусанією  *DANCE*

Подякували: 0xDADA11C71