类和Windows DC(C ++)中的奇怪数组行为?

时间:2016-10-07 19:05:16

标签: c++ arrays windows class crash

我正致力于创建一个基于文本的Windows游戏,我遇到了一个问题(我猜),在主要功能中,数组在类范围内的工作方式不同。据我所知,它是一个更大的数组类成员(或大量变量)和Windows创建DC或其他Windows API调用和/或变量之间的某种交互。

我想要做的是有一个名为Map的类,它包含一个二维Tiles数组。 Tile只是一个带有基本tile信息的简单结构。我想使数组256 x 256.就我所知,这不应该是一个问题。每个Tile应为32个字节。这个数组总共2 MB。

但是,当我在main函数中声明Map类的变量时,游戏崩溃,然后使用Windows DC执行操作。返回值似乎有所不同,在当前形式中,它通常返回255,但我也得到了#34;进程以状态-1073741571"终止。虽然128 x 128阵列在课堂上工作。如果我删除DisplayScreen中的数组或代码,它也可以正常工作。正如我暗示的那样,如果我只是将Tiles数组移动到主函数中,它也会起作用。

我真的很困惑。我不知道会有什么区别。没有什么超出范围。无论是公共会员还是私人会员都无关紧要。非动态类成员都应该在堆栈中声明,并且在类中它不应该以不同的方式工作,对吧?对不起?

有关其他信息,我使用的是Code :: Blocks和Min GW编译器。一切都是最新的。我正在运行Windows 10.我的计算机规格也不是问题,但如果重要,我有16 GB内存和4Ghz Athlon FX 8核心处理器。

编辑:这是完整的代码,因此没有遗漏任何内容

Game.h:

#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED

struct Tile
{
    char chr[2];
    int  r[2], b[2], g[2];

    bool solid;
    bool translucent;
    int  opacity;
};

class Map
{
    Tile tileMap[256][256];

public:
    Map();

};

Map::Map()
{
    int i, j;

    for(i=0;i<256;i++)
    {
        for(j=0;j<256;j++)
        {
            tileMap[i][j].chr[0] = 'X';
            tileMap[i][j].b[0] = 255;
            tileMap[i][j].r[0] = 255;
            tileMap[i][j].g[0] = 255;

            tileMap[i][j].chr[1] = ' ';
            tileMap[i][j].b[1] = 0;
            tileMap[i][j].r[1] = 0;
            tileMap[i][j].g[1] = 0;

            tileMap[i][j].solid = false;
            tileMap[i][j].translucent = false;
            tileMap[i][j].opacity = 255;
        }
    }
}

main.cpp中:

#include <windows.h>
#include "Game.h"

#define FRAMERATE 60

//Function declarations
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
void DisplayScreen(HWND pWnd, Map &pMap);

//Make the class name into a global variable
char strClassName[ ] = "GameApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpstrArgument,
                    int nCmdShow)
{
    HWND hWnd;               //This is the handle for our window
    MSG messages;            //Here messages to the application are saved
    WNDCLASSEX wndClassEx;   //Data structure for the windowclass

    Map test;

    DWORD  sysTimer;
    DWORD  sysPrevTime = 0;
    DWORD  timerDelta = 1000 / FRAMERATE;

    //Get a handle for the whole screen
    HDC hDC = GetDC(NULL);

    //Initalize the Window structure
    wndClassEx.hInstance = hThisInstance;
    wndClassEx.lpszClassName = strClassName;
    wndClassEx.lpfnWndProc = WindowProcedure;
    wndClassEx.style = CS_DBLCLKS;
    wndClassEx.cbSize = sizeof (WNDCLASSEX);
    wndClassEx.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wndClassEx.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wndClassEx.hCursor = LoadCursor (NULL, IDC_ARROW);
    wndClassEx.lpszMenuName = NULL;                 //No menu
    wndClassEx.cbClsExtra = 0;
    wndClassEx.cbWndExtra = 0;
    wndClassEx.hbrBackground = CreateSolidBrush(RGB(0,0,0));

    //Register the window class, and if it fails quit the program
    if (!RegisterClassEx (&wndClassEx))
        return 0;

    //Create Window with registered window class
    hWnd = CreateWindowEx (
        0,                           
        strClassName,                //Class name
        "Game Test",                 //Title Text
        WS_OVERLAPPEDWINDOW,         //default window type
        0,                           //X pos of window at top left
        0,                           //Y pos of window at top left
        GetDeviceCaps(hDC, HORZRES), //Set window width to screen width
        GetDeviceCaps(hDC, VERTRES), //Set window height to screen height
        HWND_DESKTOP,                //Child-window to desktop
        NULL,                        //No menu
        hThisInstance,               //Program Instance handler
        NULL);                       //No Window Creation data


    //Removes borders from the window
    SetWindowLong(hWnd, GWL_STYLE, WS_POPUP);
    //Make the window visible on the screen
    ShowWindow (hWnd, nCmdShow);

    //Run the message and game loop
    while (true)
    {
        while(PeekMessage(&messages,NULL,0,0, PM_REMOVE))
        {
            if (messages.message == WM_QUIT)
            {
                ReleaseDC(NULL, hDC);
                DestroyWindow(hWnd);
                return 0;
            }

            TranslateMessage(&messages);
            DispatchMessage(&messages);
        }

        sysTimer = timeGetTime();

        if (sysTimer >= (sysPrevTime + timerDelta) )
        {
            sysPrevTime = sysTimer;
            DisplayScreen(hWnd, test);
        }

    }
}

//This function is called by the Windows function DispatchMessage()
LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:
            PostQuitMessage (0); //Send WM_QUIT to the message queue
            break;

        default:
            return DefWindowProc (hWnd, message, wParam, lParam);
    }

    return 0;
}

void DisplayScreen(HWND pWnd, Map &pMap)
{
    HDC hDC = GetWindowDC(pWnd);
    HDC hdcBuf = CreateCompatibleDC(hDC);

    HBITMAP hbmBuf = CreateCompatibleBitmap(hDC, 800, 600);
    HFONT hMapFont = CreateFont(17,11,0,0,400,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH | FF_MODERN,"Lucida Console");
    HFONT hTxtFont = CreateFont(17,11,0,0,400,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,DEFAULT_PITCH | FF_MODERN,"Lucida Console");

    SelectObject(hdcBuf, hbmBuf);
    SelectObject(hdcBuf, hMapFont);

    SetBkColor(hdcBuf, RGB(0,0,0));
    SetTextColor(hdcBuf, RGB(255,255,255));

    //Draw to the buffer
    TextOut(hdcBuf, 10, 10, "Hello World   @", 15);

    //Tranfers the buffer to the Screen
    BitBlt(hDC, 100, 100, 800, 600, hdcBuf, 0, 0, SRCCOPY);

    //Release all object handles
    DeleteObject(hTxtFont);
    DeleteObject(hMapFont);
    DeleteObject(hbmBuf);

    DeleteDC(hdcBuf);
    ReleaseDC(pWnd, hDC);
}

即使是创建DC的某个实例,它也会崩溃。它工作正常,否则创建和销毁DC并反复显示位图,即使我离开它一小时。一旦我用它中的大数组创建了那个类,它就会死掉。

我实际上曾经将Display功能作为一个类功能,我把它移出去是因为我认为这是问题,但它不是。

有趣的是,如果我从“地图测试”中更改声明;&#39;到地图*测试=新地图;&#39;并适当地改变程序的其余部分,它的工作原理。老实说,这样做看起来有点愚蠢,而且我认为如果我没有充分的理由将所有东西放在堆上,这会减慢一切。另外,我不喜欢绷带。如果有问题,我宁愿修理它。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

你有一个堆栈溢出(条件,而不是网站)。

答案 1 :(得分:0)

这个问题可以在这个程序中重现:

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    Map test;
    return 0;
}

它失败,因为它达到了堆栈限制。

同样tileMap[i][j].chr[2]不受限制。声明为char chr[2];有效索引为0和1.它最多只能达到tileMap[i][j].chr[1]

同上b[]r[]g[]

更改Map类,以便它在堆上分配内存并修复chr

class Map
{
    //Tile tileMap[256][256];
    Tile **tileMap;
public:
    Map();
    ~Map();
};

Map::Map()
{
    int i, j;

    tileMap = new Tile*[256];
    for (i = 0; i < 256; i++)
        tileMap[i] = new Tile[256];

    for (i = 0; i<256; i++)
    {
        for (j = 0; j<256; j++)
        {
            //tileMap[i][j].chr[1] = 'X';
            tileMap[i][j].chr[0] = 'X';  //<== meant to be 0?
            tileMap[i][j].b[0] = 255;
            tileMap[i][j].r[0] = 255;
            tileMap[i][j].g[0] = 255;

            //tileMap[i][j].chr[2] = ' ';
            tileMap[i][j].chr[1] = ' '; //<== meant to be 1?
            tileMap[i][j].b[1] = 0;
            tileMap[i][j].r[1] = 0;
            tileMap[i][j].g[1] = 0;

            tileMap[i][j].solid = false;
            tileMap[i][j].translucent = false;
            tileMap[i][j].opacity = 255;
        }
    }
}

Map::~Map()
{
    int i = 0;
    for (i = 0; i < 256; i++)
        delete[]tileMap[i];
    delete[]tileMap;
}