为什么此代码会引发访问冲突异常?

时间:2013-09-24 13:17:38

标签: c++ sfml

这是我的代码:

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Text.hpp>
#include <iostream>

using namespace std;

class Game
{
    private:

        bool kratka[9];
        bool tak;

        sf::RenderWindow okno;

        sf::Image ikolo;
        sf::Image ikrzyz;

        sf::Texture tkolo;
        sf::Texture tkrzyz;

        sf::Sprite kolo[9];
        sf::Sprite krzyz[9];

        sf::Sprite minkz;
        sf::Sprite minko;

        sf::Vector2f vec;
        sf::Vector2i mouse;

        sf::Font font;

        sf::Text Gracz1;
        sf::Text Gracz2;

        sf::Text wynik1;
        sf::Text wynik2;

        sf::Texture tkrata;
        sf::Texture spowtorz;

        sf::Sprite powtorz;
        sf::Sprite skrata[9];
        int ikr[9];   // zmienne odpowiadajace za logiczna wartosc kraty
        int rzad[8]; //kombinacje rzedow

        int player1;
        int player2;

        string sp1;
        string sp2;

        void update_licznik();

        static const int krata=150;

        void process();
        void update();
        void render();

        bool jestna(sf::Sprite &sp);
        bool gracz;

    public:
        Game();
        void run();
};

Game::Game():okno(sf::VideoMode(800,600,32),"Kolko i krzyzyk")
{
    tkrata.loadFromFile("sprites/kratka.png");
    ikolo.loadFromFile("sprites/kolo.png");
    ikrzyz.loadFromFile("sprites/krzyz.png");
    spowtorz.loadFromFile("sprites/powtorz.png");
    ikrzyz.createMaskFromColor(sf::Color(255,255,255),0);
    ikolo.createMaskFromColor(sf::Color(255,255,255),0);

    okno.setFramerateLimit(30);

    tkolo.loadFromImage(ikolo);
    tkrzyz.loadFromImage(ikrzyz);

    minkz.setTexture(tkrzyz);
    minkz.setPosition(670,270);
    minkz.setScale(0.7,0.7);

    minko.setTexture(tkolo);
    minko.setPosition(0,270);
    minko.setScale(0.7,0.7);

    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            kolo[3*i+j].setTexture(tkolo);
            krzyz[3*i+j].setTexture(tkrzyz);
            kolo[3*i+j].setPosition(i*150+175,j*150+75);
            krzyz[3*i+j].setPosition(i*150+175,j*150+75);
        }
    }

    font.loadFromFile("sprites/poseiAOE.ttf");
    Gracz1.setFont(font);
    Gracz1.setString("Gracz 1");
    Gracz1.setCharacterSize(70);

    Gracz2.setFont(font);
    Gracz2.setString("Gracz 2");
    Gracz2.setCharacterSize(70);
    Gracz2.setPosition(650,0);

    wynik1.setFont(font);
    wynik2.setFont(font);
    wynik1.setCharacterSize(300);
    wynik2.setCharacterSize(300);
    wynik1.setPosition(25,0);
    wynik2.setPosition(700,0);

    powtorz.setTexture(spowtorz);
    powtorz.setPosition(640,440);

    player2=0;
    player2=0;

    for(int i=0;i<9;i++)
    {
        ikr[i]=0;
        rzad[i]=0;
    }
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            skrata[3*i+j].setTexture(tkrata);
            skrata[3*i+j].setPosition(i*150+175,j*150+75);
        }
    }


}

void Game::update_licznik()
{
    sp1=to_string(player1);
    sp2=to_string(player2);
    wynik1.setString(sp1);
    wynik2.setString(sp2);
}


bool Game::jestna(sf::Sprite &sp)
{
    vec=sp.getPosition();
    mouse=sf::Mouse::getPosition(okno);

    if(mouse.x>vec.x && mouse.x<vec.x+krata && mouse.y>vec.y && mouse.y<vec.y+krata)
        return true;
    else
        return false;
}

void Game::process()
{
    sf::Event zdarzenie;
    while(okno.pollEvent(zdarzenie))
    {
        for(int i=0;i<9;i++)
        {
            if(zdarzenie.type==sf::Event::MouseButtonPressed && jestna(skrata[i]) && ikr[i]==0)
            {
                gracz=!gracz;
                if(gracz)
                    ikr[i]++;
                else
                    ikr[i]--;
            }   
            if(zdarzenie.type==sf::Event::MouseButtonPressed && jestna(powtorz))
            {
                for(int i=0;i<9;i++)
                {
                    ikr[i]=0;
                }
            }
        }

        if(zdarzenie.type==sf::Event::Closed)
            okno.close();
    }
}

void Game::update()
{
    update_licznik();
    rzad[0]=ikr[0]+ikr[1]+ikr[2];
    rzad[1]=ikr[0]+ikr[3]+ikr[6];
    rzad[2]=ikr[2]+ikr[5]+ikr[8];
    rzad[3]=ikr[6]+ikr[7]+ikr[8];
    rzad[4]=ikr[3]+ikr[4]+ikr[5];
    rzad[5]=ikr[1]+ikr[4]+ikr[7];
    rzad[6]=ikr[0]+ikr[4]+ikr[8];
    rzad[7]=ikr[2]+ikr[4]+ikr[6];
    for(int i=0;i<8;i++)
    {
        if(rzad[i]==3)
        {
            player1++;
            rzad[i]=0;
            for(int i=0;i<9;i++)
                ikr[i]=0;

        }
        if(rzad[i]==-3)
        {
            player2++;
            rzad[i]=0;
            for(int i=0;i<9;i++)
                ikr[i]=0;
        }
    }
}

void Game::render()
{
    okno.clear();
    for(int i=0;i<9;i++)
    {
        okno.draw(skrata[i]);
        if(ikr[i]==1)
            okno.draw(kolo[i]);
        if(ikr[i]==-1)
            okno.draw(krzyz[i]);
    }
    okno.draw(Gracz1);
    okno.draw(Gracz2);
    okno.draw(wynik1);
    okno.draw(wynik2);
    okno.draw(powtorz);
    okno.draw(minkz);
    okno.draw(minko);
    okno.display();
}

void Game::run()
{
    while(okno.isOpen())
    {
        process();
        update();
        render();
    }
}

int main()
{
    Game game;
    game.run();
    return 0;
}

每次运行此代码时,都会出现以下异常:

Unhandled exception at 0x505D4361 (msvcr110d.dll) in Gra1.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC

1 个答案:

答案 0 :(得分:-1)

崩溃的地方主要是什么,你应该用调试器搞清楚,但看看代码,有很多错误。

由于SFML/Text.hpp不是有效的标题,上面的代码甚至不应该编译。

using namespace std;主要是一件坏事,如果它在全球范围内完成,那么这样做是完全错误的。命名空间用于a)防止名称冲突和b)明确表示类的起源,因此在大多数情况下,您不应该是using名称空间。

每个变量都需要初始化。如果它是一个带有默认构造函数的类,则不必执行任何操作,但如果它是intbool,则必须对其进行初始化,否则您将运行未定义的应用程序行为,这意味着它可能随时爆炸。由于您正在使用类,因此您应该在构造函数的初始化列表中初始化变量,就像使用窗口一样。

正如ch0kee在评论中指出的那样,rzad会遇到溢出。不幸的是,应用程序可能仍然继续运行,因为在数组中最后一个元素之后访问元素保证是一个有效的指针,如果你为它指定0,你可能会在某些情况下幸运。即使“指针”有效,您也不应该写入或读取其基础内容。您可以使用std::vector或C ++ 11 std::array来阻止此类问题,它将数据与其大小相结合,从而允许进行准确且无错误的边界检查。

proccess()update()中,您使用for循环来迭代数组,但是您使用了多次索引变量i,从而掩盖了其他指数。你应该总是对嵌套循环使用不同的索引,不仅可以使用更高的索引,还可以减少混淆。

最后,您可能希望用英语编写变量名称。使用您的母语进行编程是可以的,但是一旦您向非本地语言的人寻求帮助,另一个人就会在理解您的应用程序的含义时遇到问题。

如果你修复了上述所有内容,它就不会崩溃了。顺便说一下,在编译时激活更高级别的错误检查是有价值的,因为它已经通过警告告诉你很多错误。