0x00000000 でハンドルされていない例外が発生しました

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
よーあん
記事: 3
登録日時: 12年前
連絡を取る:

0x00000000 でハンドルされていない例外が発生しました

#1

投稿記事 by よーあん » 12年前

 C言語初心者です。用語など間違っている部分があると思いますが、よろしくおねがいします。

 最近、龍神録プログラミングと新・ゲームプログラミングの館を参考に、
 龍神録のプログラムをC++風に書き換えて遊んでいるのですが、13章でどうしてもわからないことに出会ったので質問です。

 まず、13章のように敵と弾の処理をごっちゃにしたくなかったので、敵は敵、弾は弾で分けることにしました。
 また、新・ゲームプログラミングの館を参考にEnemyMgr→Enemy,EnemyPattern,ShotMgr→Shot,ShotPatternといった具合にマネージャを介するようにしています。

 そこで、13章の敵弾パターンの関数を配列に入れる部分を以下のように、コンストラクタで関数へのポインタを配列に放り込み、
 それを必要な時にvoid CEnemyShotPattern::Patternで呼び出して使うようにしました。

 すると、ビルド時には問題が無いのですが、プログラムが実行、ウィンドウ表示から60フレーム後の敵の初弾発生時に
 「GameProg.exe の 0x00000000 でハンドルされていない例外が発生しました: 0xC0000005: Access violation」
 というエラーが発生し、プログラムが止まるようになりました。

 ブレークポイントを色々設置して問題点を考えてみたのですが、
 どうやら、敵弾パターンの関数ポインタが入った配列mShotPattern[7]の中身の値(mShotPattern[0]~[6])が全てアドレス0x00000000を参照していることが問題のようです。
 しかし、コンストラクタ実行後にブレークポイントを入れてみると、各mShotPatternは0x00000000以外の値を持っており、この書き方に問題があるわけではなさそうです。
 (this->*mShotPattern[num])(Player,Enemy,Shot);の行に至るまではその値を保持しているのですが、この行に至った際に先程のエラーがでてしまいます。

 もしかしたらこれが原因ではないのかもしれませんが、どなたか原因のわかる方がいらっしゃいましたらご教授ください。

 OS:Windows8
 コンパイラ:VC++2010Express

コード:

//EnemyShotPattern.h
#ifndef DEF_ENEMYSHOTPATTERN_H //二重include防止
#define DEF_ENEMYSHOTPATTERN_H

#include "EnemyShot.h"
#include "EnemyMgr.h"
#include "PlayerMgr.h"
#include "Music.h"
#include "define.h"
#include "math.h"


#define SHOT_KND_MAX 7

class CEnemyShotPattern:public CEnemyShot{

	private:
		void BulletP_H000(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot );		//n:オブジェクト番号
		void BulletP_H001(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot );		//n:オブジェクト番号
		void BulletP_H002(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot );		//n:オブジェクト番号
		void BulletP_H003(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot );		//n:オブジェクト番号
		void BulletP_H004(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot );		//n:オブジェクト番号
		void BulletP_H005(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot );		//n:オブジェクト番号
		void BulletP_H006(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot );		//n:オブジェクト番号

		double Shotatan2(Player_t *Player,Enemy_t *Enemy);
		int Search(Shot_t *Shot);
		double rang(double ang){
			return ( -ang + ang*2 * GetRand(10000)/10000.0 );
		}
		void (CEnemyShotPattern::*mShotPattern[SHOT_KND_MAX])(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot);
	public:
		CEnemyShotPattern(){
			memset(&mShotPattern[0],0,sizeof(mShotPattern[SHOT_KND_MAX]));
			mShotPattern[0]=&CEnemyShotPattern::BulletP_H000;
			mShotPattern[1]=&CEnemyShotPattern::BulletP_H001;
			mShotPattern[2]=&CEnemyShotPattern::BulletP_H002;
			mShotPattern[3]=&CEnemyShotPattern::BulletP_H003;
			mShotPattern[4]=&CEnemyShotPattern::BulletP_H004;
			mShotPattern[5]=&CEnemyShotPattern::BulletP_H005;
			mShotPattern[6]=&CEnemyShotPattern::BulletP_H006;
		}			//コンストラクタで関数ポインタを配列に格納

		void Pattern(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot, int num){
			(this->*mShotPattern[num])(Player,Enemy,Shot);  //num:パターン番号
		}

		~CEnemyShotPattern(){}
};
#endif

katariya
記事: 11
登録日時: 12年前

Re: 0x00000000 でハンドルされていない例外が発生しました

#2

投稿記事 by katariya » 12年前

クラスに所属しているメソッドは生成後に初めてアドレスが割り当てられるためです。
Cだと全ての関数はアドレスをもってますが、メソッドは持ちません。
なのでこの入れ方をするのであれば全てのBulletPをstaticにするというとてもクラスプログラムらしからぬ方法をとらないといけません。

もう一つは継承を使い、BulletP基底クラスを継承したクラスを使ったプログラムなどはどうでしょうか。

コード:

class IBulletPBase
{
public:
     IBulletPBase()
     virtual ~IBulletPBase(); 
     virtual void Pattern(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot) = 0;
};

class CBulletP_H000 : public IBulletPBase
{
public:
     CBulletP_H000()
     virtual ~CBulletP_H000(); 
     void Pattern(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot);   // 実行の中身を書く
};
…// それぞれのパターンに関してクラスを作る

//==========================================================
//EnemyShotPattern.h
//==========================================================
#ifndef DEF_ENEMYSHOTPATTERN_H //二重include防止
#define DEF_ENEMYSHOTPATTERN_H
 
#include "EnemyShot.h"
#include "EnemyMgr.h"
#include "PlayerMgr.h"
#include "Music.h"
#include "define.h"
#include "math.h"
#include "bulletPBase.h"
#include "bulletP_H000.h"
… // 弾のパターンをインクルード

#define SHOT_KND_MAX 7
 
class CEnemyShotPattern:public CEnemyShot{
 
    private:
        IBulletPBase* mShotPattern[SHOT_KND_MAX];
    public:
        CEnemyShotPattern(){
            mShotPattern[0]= new CBulletP_H000();
            mShotPattern[1]= new CBulletP_H001();
            mShotPattern[2]= new CBulletP_H002();
            mShotPattern[3]= new CBulletP_H003();
            mShotPattern[4]= new CBulletP_H004();
            mShotPattern[5]= new CBulletP_H005();
            mShotPattern[6]= new CBulletP_H006();
        }           //コンストラクタでそれぞれの振る舞いクラスを配列にnewしてあげる
 
        void Pattern(Player_t *Player,Enemy_t *Enemy, Shot_t *Shot, int num){
            this->mShotPattern[num]->Pattern(Player,Enemy,Shot);  //num:パターン番号
        }
 
        ~CEnemyShotPattern()
    {
      for(int nCnt = 0; nCnt < SHOT_KND_MAX ; ++nCnt)
             {
                    delete mShotPattern[num];
                    mShotPattern[num] = NULL;
             }
    }
};
#endif
C++とCの違いの一つに関数がアドレスをどう持つかというのがあるので気をつけてみてください。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: 0x00000000 でハンドルされていない例外が発生しました

#3

投稿記事 by ISLe » 12年前

関数名を使える時点でメンバ関数も固有のアドレスを持ってますよ。

提示されたコード自体に問題はないようです。

関数テーブルはインスタンスごとに持っているわけですが、破壊されたインスタンスと破壊されていないインスタンスをきちんと区別できていますか?

とりあえず、CEnemyShotPatternを使った宣言の前後に配列の宣言があったら、それに対して添字外のアクセスをしていないか調べてみてください。

katariya
記事: 11
登録日時: 12年前

Re: 0x00000000 でハンドルされていない例外が発生しました

#4

投稿記事 by katariya » 12年前

ISLe さんが書きました: 関数名を使える時点でメンバ関数も固有のアドレスを持ってますよ。
お恥ずかしい限りです。確かにその通りでした。勉強不足ですいません…。
そうするとAccessViolationなので領域外アクセスなので配列外アクセスくらいですかね…。

よーあん
記事: 3
登録日時: 12年前
連絡を取る:

Re: 0x00000000 でハンドルされていない例外が発生しました

#5

投稿記事 by よーあん » 12年前

ISLeさん、katariyaさん

返信ありがとうございます。
もう一度、確認し次第ここに返信いたします。

よーあん
記事: 3
登録日時: 12年前
連絡を取る:

Re: 0x00000000 でハンドルされていない例外が発生しました

#6

投稿記事 by よーあん » 12年前

ISLeさん、katariyaさん

突破できました!ありがとうございました!!
Shotの配列の初期化部分で意味不明な文が書いてあったために、起こったようでした。
初期化位置と文を書き換えて直しました。

閉鎖

“C言語何でも質問掲示板” へ戻る