PDCurses in C (продолжает показывать место чтения нарушения прав доступа)

Я только вчера начал новый проект (рогалик). Это мой первый, и я продолжаю сталкиваться с той же ошибкой. После попытки реализовать карту прокрутки я запустил программу, но всякий раз, когда я нажимал клавишу, Visual Studio показывала окно сообщения о том, что имеется место чтения с нарушением прав доступа.

Вот код:

#include "curses.h"
#include <stdlib.h>

#define MAX_HEIGHT 16
#define MAX_WIDTH 21

typedef struct tile
{
    char *tile;
    bool passable;
}tile;

typedef struct player
{
    int xpos;
    int ypos;
    int dx;
    int dy;
}player;

tile tileArray[] = {
    {".",TRUE},
    {"#",FALSE},
    {"+",FALSE},
    {"/",TRUE}
};

int mapArray[15][21] = {
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,1,1,1,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }

};

typedef struct camPos
{
    int y;
    int x;
}camPos;

void initSetup();
player *actorSetup();
void refreshScreenMap();
void handleInput();
void drawScreenMap();
void interactionOpen();
bool isPassable(int y, int x);
void startupScreen();

player *user;
camPos cam;

int main()
{
    initSetup();

    user = actorSetup();
    cam.y = 2;
    cam.x = 2;

    startupScreen();

    while (TRUE) 
    {
        drawScreenMap();
        refreshScreenMap();
        handleInput();
        clear();
    }
    endwin();
    return 0;
}

void initSetup()
{
    initscr();
    noecho();
    raw();
    keypad(stdscr,TRUE);
}

player *actorSetup()
{
    player *newactor;
    newactor = malloc(sizeof(player));
    newactor->xpos = 10;
    newactor->ypos = 10;
    return newactor;
}

void handleInput()
{
    char button = getch();
    switch (button)
    {
        case 's':
            user->dy++;
            break;
        case 'w':
            user->dy--;
            break;
        case 'a':
            user->dx--;
            break;
        case 'd':
            user->dx++;
            break;
        case 'o':
            interactionOpen(user);
            break;
    }
    if (isPassable(user->ypos + user->dy, user->xpos + user->dx))
    {
        user->ypos += user->dy;
        user->xpos += user->dx;
    }
    else
    {
        user->dx = 0;
        user->dy = 0;
    }
}

void refreshScreenMap()
{
    mvprintw(6, 8, "@");
    cam.x += user->dx;
    cam.y += user->dy;
}

void drawScreenMap()
{
    for (int y = 1; y < 12; y++)
    {
        move(y,1);
        for (int x = 1; x < 16; x++)
        { 
            mvprintw(y, x, tileArray[mapArray[cam.y + y][cam.x + x]].tile);
        }
    }
}

void interactionOpen()
{
    if (mapArray[user->ypos + 1][user->xpos] == 2)
    {
        mapArray[user->ypos + 1][user->xpos] = 3;
    }
    else if (mapArray[user->ypos - 1][user->xpos] == 2)
    {
        mapArray[user->ypos - 1][user->xpos] = 3;
    }
    else if (mapArray[user->ypos][user->xpos + 1] == 2)
    {
        mapArray[user->ypos][user->xpos + 1] = 3;
    }
    else if (mapArray[user->ypos][user->xpos - 1] == 2)
    {
        mapArray[user->ypos][user->xpos - 1] = 3;
    }
    else if (mapArray[user->ypos + 1][user->xpos] == 3)
    {
        mapArray[user->ypos + 1][user->xpos] = 2;
    }
    else if (mapArray[user->ypos - 1][user->xpos] == 3)
    {
        mapArray[user->ypos - 1][user->xpos] = 2;
    }
    else if (mapArray[user->ypos][user->xpos + 1] == 3)
    {
        mapArray[user->ypos][user->xpos + 1] = 2;
    }
    else if (mapArray[user->ypos][user->xpos - 1] == 3)
    {
        mapArray[user->ypos][user->xpos - 1] = 2;
    }
}

bool isPassable(int y, int x)
{
    bool pass = tileArray[mapArray[y][x]].passable;
    if (pass == FALSE)
    {
        return FALSE;
    }
    else if (y < cam.y || y >= (cam.y + 11))
    {
        return FALSE;
    }
    else if (x < cam.x || x >= (cam.x + 15))
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

void startupScreen()
{
    mvprintw(10, 20, "________");
    mvprintw(11, 20, "\\______ \\  __ __  ____    ____   ____  ____   ____  ");
    mvprintw(12, 20, " |    |  \\|  |  \\/    \\  / ___\\_/ __ \\/  _ \\ /    \\ ");
    mvprintw(13, 20, " |    `   \\  |  /   |  \\/ /_/  >  ___(  <_> )   |  \\ ");
    mvprintw(14, 20, "/_______  /____/|___|  /\\___  / \\___  >____/|___|  / ");
    mvprintw(15, 20, "        \\/           \\//_____/      \\/           \\/");
    mvprintw(16, 20, "Made by Will Reid");
    mvprintw(17, 20, "Press any key to start...");
    getch();
    clear();
}

person Will Reid    schedule 15.02.2017    source источник
comment
Где точно происходит сбой? Пожалуйста, используйте отладчик и сообщите нам, какая строка вызывает segfault.   -  person Yuriy Ivaskevych    schedule 15.02.2017
comment
Необработанное исключение по адресу 0x00221CD5 в Game.exe: 0xC0000005: место чтения с нарушением прав доступа 0xBEE161B4. (Сообщение от Visual Studios) Строка ;bool pass = tileArray[mapArray[y][x]].passable; (в функции isPassable) Однако, когда я изменяю проход на равный TRUE, точка останова перемещается на ;mvprintw(y, x,tileArray[mapArray[cam.y + y][cam.x + x]].tile); (в функции drawScreenMap). Спасибо, что заглянули!   -  person Will Reid    schedule 15.02.2017
comment
Просто догадки: возможно, вы используете неправильные индексы в массиве. Я предлагаю вам создать две функции: int getMapValue(int x, int y); и bool setMapValue(int x, int y, int value);. Используйте эти функции всякий раз, когда обращаетесь к файлу mapArray. Затем вы можете добавить код, чтобы убедиться, что ваши индексы находятся в диапазоне. Если это не так, выведите ошибку.   -  person Johnny Mopp    schedule 15.02.2017
comment
Добро пожаловать в Stack Overflow! Пожалуйста, отредактируйте свой код, уменьшив его до минимально воспроизводимый пример вашей проблемы. Ваш текущий код включает в себя много второстепенного по отношению к вашей проблеме — минимальный пример обычно похож на хороший модульный тест: выполняется только одна задача с входными значениями, указанными для воспроизводимости.   -  person Toby Speight    schedule 15.02.2017
comment
@Johnny Mopp Я сделал, как вы предложили, и точка останова переместилась на ;mapValue = mapArray[y][x]; в функции getMapValue. Есть ли проблема в том, как я могу получить значение из массива? Спасибо   -  person Will Reid    schedule 15.02.2017
comment
@ Тоби Спейт, я попробую изменить его завтра (так как в Гонконге уже довольно поздно). Мой код выглядит довольно грязно XD   -  person Will Reid    schedule 15.02.2017


Ответы (1)


Проблема в том, что переменная cam, используемая в isPassable, не была инициализирована.

Я использовал valgrind (в Linux), чтобы увидеть это:

==11010== 1 errors in context 1 of 7:
==11010== Invalid read of size 8
==11010==    at 0x400B72: drawScreenMap (foo.c:151)
==11010==    by 0x40091E: main (foo.c:77)
==11010==  Address 0x58e8c2a0 is not stack'd, malloc'd or (recently) free'd
==11010==
==11010==
==11010== 7 errors in context 2 of 7:
==11010== Conditional jump or move depends on uninitialised value(s)
==11010==    at 0x40100E: isPassable (foo.c:203)
==11010==    by 0x400A46: handleInput (foo.c:124)
==11010==    by 0x400928: main (foo.c:79)
==11010==  Uninitialised value was created by a heap allocation
==11010==    at 0x4C28BED: malloc (vg_replace_malloc.c:263)
==11010==    by 0x400974: actorSetup (foo.c:97)
==11010==    by 0x4008F9: main (foo.c:69)

Кроме того, включение предупреждений компилятора показало несколько проблем (в Visual Studio есть предупреждения компилятора...).

person Thomas Dickey    schedule 18.02.2017