为啥这段代码会抛出访问冲突异常?

Posted

技术标签:

【中文标题】为啥这段代码会抛出访问冲突异常?【英文标题】:Why does this code throw an access violation exception?为什么这段代码会抛出访问冲突异常? 【发布时间】:2013-09-24 13:17:38 【问题描述】:

这是我的代码:

#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

【问题讨论】:

您应该减少代码以获得sscce。它有助于发现你崩溃的地方。此外,调试器将帮助 很多 Game 构造函数中rzad[i]=0; 将在最后一次迭代中由于rzad[8] 而溢出。另外,你初始化player2 两次,你省略了player1 【参考方案1】:

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

上面的代码甚至不应该编译,因为SFML/Text.hpp 不是一个有效的标头。

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

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

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

proccess()update() 中,您使用for 循环来迭代数组,但是您多次使用索引变量i,从而使其他索引黯然失色。您应该始终为嵌套循环使用不同的索引,不仅可以使用更高层的索引,还可以减少混淆。

最后,您可能希望用英文编写变量名。使用您的母语进行编程是可以的,但是一旦您向非该语言母语的人寻求帮助,其他人就会难以理解您的应用程序的含义。

如果您解决了上述所有问题,它应该不会再崩溃了。顺便说一句,在编译时激活更高级别的错误检查是一件很有价值的事情,因为它已经通过警告告诉你很多错误。

【讨论】:

使用命名空间信息是对的,但在这种情况下,它似乎只是一个大的 mama cpp 文件,所以为了测试,使用命名空间更容易,打字更少。但你是对的,永远不要将using 语句放在头文件中。

以上是关于为啥这段代码会抛出访问冲突异常?的主要内容,如果未能解决你的问题,请参考以下文章

为什么调试器会抛出“读取访问冲突。这是nullptr”例外吗?

为啥非空列表会抛出空指针异常?

为啥即使使用了调用,组合框也会抛出异常

为啥这段代码会抛出 java.lang.***Error [重复]

为啥这段代码会抛出 ReferenceError: test is not defined?

为啥geoip会抛出异常?