プログラムが停止してしまう

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

プログラムが停止してしまう

#1

投稿記事 by Iseuma14 » 3年前

たびたび質問失礼します
私は現在、龍神録プログラミングの館を参考にしながら、自分なりにポインタを使ってグローバル変数を使わないようにしてプログラムを組んでおります
そこそこスムーズに進んでいたのですが、11章、エクセルを使って敵の出現データを作ってみよう(http://dixq.net/rp/11.html)で詰んでしまいました
具体的にはプログラムを実行すると、黒い画面が表示された数秒の後フリーズし、プログラムが停止しましたのウインドウが表示されます
以下ソースコードです 全てを貼ると非常に長くなってしまうため10章からの変更、追加点及びに関係しそうな部分のみ添付させていただきます

コード:

//main.cpp
#include "DxLib.h"
#include "struct.h"
#include "load.h"
#include "graph.h"
#include "player.h"
#include "define.h"
#include "enemy.h"

int key_update(int*);
int check_shift(int,int);


int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	ChangeWindowMode(TRUE),DxLib_Init(),SetDrawScreen(DX_SCREEN_BACK);
	int key[256],board,stage_count=0,fanction=0;
	ch_t player;
	enemy_t enemy[ENEMY_MAX];
	enemy_t enemy_order[ENEMY_ORDER_MAX]; 
	player.x = 160.0;
	player.y = 300.0;
	load_graph(&player.img,&board,enemy);
	load_story(enemy_order);
	while(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0)
	{
		stage_count++;
		graph_ch(&player);
		graph_enemy(enemy);
		graph_board(&board);
		key_update(key);
		if(key[KEY_INPUT_RSHIFT] > 0||key[KEY_INPUT_LSHIFT] > 0)
			slow_move(&player,key);		

		else if(key[KEY_INPUT_UP]>0 || key[KEY_INPUT_RIGHT]>0 || key[KEY_INPUT_DOWN]>0 || key[KEY_INPUT_LEFT]>0)
			quick_move(&player,key);

		enemy_enter(enemy,&stage_count,enemy_order);
		enemy_action(enemy,&stage_count);		

	}
	DxLib_End();
	return 0;
}


int key_update(int key[])
{
	char all_key[256];
	GetHitKeyStateAll(all_key);
	int i;
	for(i=0;i<256;i++)
	{
		if(all_key[i] != 0)
			key[i]++;
		else
			key[i] = 0;
	}
	return 0;
}

//ここまでmain.cpp、ここから↓graph.cpp
#include "DxLib.h"
#include "struct.h"
#include "graph.h"
#include "define.h"

int graph_ch(ch_t *player)
{
	DrawGraph(player->x,player->y,player->img,TRUE);
	return 0;
}

int graph_board(int *board)
{
	DrawGraph(0,0,*board,TRUE);
	return 0;
}

int graph_enemy(enemy_t *enemy)
{
	int i;
	for(i=0;i<30;i++)
	{
		if(enemy[i].flag == 1)
		{
			DrawRotaGraph(enemy[i].x,enemy[i].y,0.5,0.0,enemy[i].img,TRUE);
		}
	}
	
	return 0;
}
//ここまでgraph.cpp、ここから↓load.cpp
#include "DxLib.h"
#include "define.h"
#include "struct.h"
#include "load.h"
int load_graph(int *player,int *board,enemy_t *enemy)
{
	*player = LoadGraph("画像/キャラクタ01.png");
	*board = LoadGraph("画像/board.png");
	int i;
	for(i=0;i<ENEMY_MAX;i++)
	{
		enemy[i].img = LoadGraph("画像/雑魚.png");
	}
	return 0;
}

int load_story(enemy_t *enemy_order)
{
	int n,num,i,fp;
	int input[64];
	char inputc[64];

	fp = FileRead_open("date/storyH0.csv");
	if(fp == NULL)
	{
		printfDx("error");
		return -1;
	}
	for(i=0;i<2;i++)
	{
		while(FileRead_getc(fp)!='\n')
		{
			while(FileRead_getc(fp)!='\n');
		}

	}
	n = 0,num = 0;
	while(1)
	{
		for(i=0;i<64;i++)
		{

			inputc[i]=input[i]=FileRead_getc(fp);//1文字取得する
            if(inputc[i]=='/')
			{
				while(FileRead_getc(fp)!='\n');//改行までループ
				i=-1;//カウンタを最初に戻して
				continue;
            }
            
			if(input[i]==',' || input[i]=='\n')
			{
                inputc[i]='\0';
                break;
            }
                        
			if(input[i]==EOF)
	     	{
				FileRead_close(fp);
				return 0;
            }

		}
		switch(num)
		{
            case 0: enemy_order[n].count    =atoi(inputc);break;
            case 1: enemy_order[n].pattern  =atoi(inputc);break;
            case 2: enemy_order[n].kind     =atoi(inputc);break;
            case 3: enemy_order[n].x        =atof(inputc);break;
            case 4: enemy_order[n].y        =atof(inputc);break;
            case 5: enemy_order[n].sp       =atof(inputc);break;
            case 6: enemy_order[n].bltime   =atoi(inputc);break;
            case 7: enemy_order[n].blknd    =atoi(inputc);break;
            case 8: enemy_order[n].color    =atoi(inputc);break;
            case 9: enemy_order[n].hp       =atoi(inputc);break;
            case 10:enemy_order[n].blknd2   =atoi(inputc);break;
            case 11:enemy_order[n].wait     =atoi(inputc);break;
            case 12:enemy_order[n].item_n[0]=atoi(inputc);break;
            case 13:enemy_order[n].item_n[1]=atoi(inputc);break;
            case 14:enemy_order[n].item_n[2]=atoi(inputc);break;
            case 15:enemy_order[n].item_n[3]=atoi(inputc);break;
            case 16:enemy_order[n].item_n[4]=atoi(inputc);break;
            case 17:enemy_order[n].item_n[5]=atoi(inputc);break;
        }
        num++;
                
		if(num==18)
		{
	       num=0;
           n++;
        }
	}
	return 0;
}
//ここまでload.cpp、ここから↓enemy.cpp
#include "DxLib.h"
#include "struct.h"
#include "enemy.h"
#include "define.h"

int enemy_pattern0(enemy_t **enemy,int *i)
{
	if((*enemy[*i]).count == 0)
		(*enemy[*i]).vy += 2;

	if((*enemy[*i]).count == 60)
		(*enemy[*i]).vy += 0;

	if((*enemy[*i]).count == 60+(*enemy[*i]).wait)
		(*enemy[*i]).vy -= 2;

	return 0;
}

int enemy_flag_search(enemy_t **enemy)
{
	int i;
	for(i=0;i<ENEMY_MAX;i++)
	{
		if((*enemy[i]).flag == 0)
			return i;
	}
	return -1;

}


int enemy_enter(enemy_t *enemy,int *stage_count,enemy_t *enemy_order)
{
	int i,j,t;
	for(t=0;t<ENEMY_ORDER_MAX;t++)
	{
		if(enemy_order[t].count == *stage_count)
		{
			 if(i=enemy_flag_search(&enemy) != -1)
			 {
				enemy[i].flag   =1;//フラグ
                enemy[i].count  =0;//カウンタ
                enemy[i].pattern=enemy_order[t].pattern;//移動パターン
                enemy[i].muki   =1;//向き
                enemy[i].kind   =enemy_order[t].kind;//敵の種類
                enemy[i].x      =enemy_order[t].x;//座標
                enemy[i].y      =enemy_order[t].y;
                enemy[i].sp     =enemy_order[t].sp;//スピード
                enemy[i].bltime =enemy_order[t].bltime;//弾の発射時間
                enemy[i].blknd  =enemy_order[t].blknd;//弾幕の種類
                enemy[i].blknd2 =enemy_order[t].blknd2;//弾の種類
                enemy[i].color  =enemy_order[t].color;//色
                enemy[i].wait   =enemy_order[t].wait;//停滞時間
                enemy[i].hp     =enemy_order[t].hp;//体力
                enemy[i].hp_max =enemy[i].hp;//体力最大値
                enemy[i].vx     =0;//水平成分の速度
                enemy[i].vy     =0;//鉛直成分の速度
                enemy[i].ang    =0;//角度
                for(j=0;j<6;j++)
				{
					enemy[i].item_n[j]=enemy_order[t].item_n[j];//落とすアイテム
                }
			 }
		}
	}
	return 0;
}



int enemy_action(enemy_t *enemy,int *stage_count)
{
	int i;
	for(i=0;i<ENEMY_MAX;i++)
	{
		if(enemy[i].flag == 1)
		{
			enemy_pattern0(&enemy,&i);
			enemy[i].count++;
		}

		if(enemy[i].x < -30 || enemy[i].x > 500 || enemy[i].y < -30 || enemy[i].y > 500)
			enemy[i].flag = 0;
	}

	return 0;
}
//ここまでenemy.cpp、ここからstruct.h
#ifndef INCLUDE_STRUCT
#define INCLUDE_STRUCT
struct ch_t
{
        int flag;       //フラグ
        int cnt;        //カウンタ
        int power;      //パワー
        int point;      //ポイント
        int score;      //スコア
        int num;        //残機数
        int mutekicnt;  //無敵状態とカウント
        int shot_mode;  //ショットモード
        int money;      //お金
        int img;        //画像
        int slow;       //スローかどうか
        double x,y;     //座標
};

struct enemy_t
{
        int flag;		//フラグ
		int count;		//カウンタ
		int pattern;	//移動パターン
		int muki;		//向き
		int kind;		//種類
		int hp;			//体力
		int hp_max;		//最大体力
		int item_n[6];	//アイテム
		int img;		//画像
       
        double x;	//座標x
		double y;	//座標y
		double vx;	//x速度
		double vy;	//y速度
		double sp;	//スピード
		double ang;	//角度

        int bltime;	//弾幕開始時間
		int blknd;	//弾幕の種類
		int blknd2;	//弾の種類
		int color;	//色
		int state;	//状態
		int wtime;	//待機時間
		int wait;	//停滞時間
};


#endif
//ここまでstruct.h,ここから↓define.h
#ifndef DEFINE_INCLUDE
#define DEFINE_INCLUDE

#define WHITE GetColor(255,255,255)

#define ENEMY_MAX 30

#define X_MIN -8

#define Y_MIN -37

#define X_MAX 351

#define Y_MAX 361

#define ENEMY_ORDER_MAX 500

#endif
長くて見づらいかもしれません 申し訳ございません
ヒントだけでも教えていただけるとうれしいです
よろしくお願いします

アバター
プラム
記事: 164
登録日時: 6年前
住所: 東海地方

Re: プログラムが停止してしまう

#2

投稿記事 by プラム » 3年前

VC++で作業をしているのであれば。「デバック実行」という機能を使ってみると良いかもしれません。

どこのコードで不具合を起こしているかと、不具合の内容をVC++さんが教えてくれます。

アバター
みけCAT
記事: 6246
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: プログラムが停止してしまう

#3

投稿記事 by みけCAT » 3年前

enemy_flag_search()関数内の*enemyはenemy[0]と等価であり、
enemy_pattern0()関数内の*enemy[*i]はenemy[*i][0]と等価であるので、iや*iが0でない時は確保されていない場所にアクセスしてしまいます。
それぞれ(*enemy)、(*enemy)[*i]とするか、無駄にポインタのポインタを使うのをやめるといいでしょう。

また、enemy_enter()関数内の条件式 i=enemy_flag_search(&enemy) != -1 は、比較の結果をiに代入しているので、
iは0か1にしかならないはずです。これは意図した動作ですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Iseuma14
記事: 54
登録日時: 4年前

Re: プログラムが停止してしまう

#4

投稿記事 by Iseuma14 » 3年前

>>ノウル様、ご回答ありがとうございます
デバッグ機能使ったことないので試させてもらいます!

Iseuma14
記事: 54
登録日時: 4年前

Re: プログラムが停止してしまう

#5

投稿記事 by Iseuma14 » 3年前

>>みけCAT様、いつも回答ありがとうございます
みけCAT さんが書きました:enemy_flag_search()関数内の*enemyはenemy[0]と等価であり、
enemy_pattern0()関数内の*enemy[*i]はenemy[*i][0]と等価であるので、iや*iが0でない時は確保されていない場所にアクセスしてしまいます。
それぞれ(*enemy)、(*enemy)[*i]とするか、無駄にポインタのポインタを使うのをやめるといいでしょう。

また、enemy_enter()関数内の条件式 i=enemy_flag_search(&enemy) != -1 は、比較の結果をiに代入しているので、
iは0か1にしかならないはずです。これは意図した動作ですか?


まず言うまでもなくenemy_enter内の条件式は誤りですね 括弧をつけるようにします
動かない直接の原因としては、load_story関数内のwhileの中になぜか同じものを書いており、ループを抜け出せないのが原因でした お恥ずかしい限りです。

みけCAT様のご回答についていくつかお聞かせいただきたいものがございます
みけCAT さんが書きました:enemy_flag_search()関数内の*enemyはenemy[0]と等価であり、
enemy_pattern0()関数内の*enemy[*i]はenemy[*i][0]と等価であるので、iや*iが0でない時は確保されていない場所にアクセスしてしまいます。

とありますが、なぜダブルポインタが二次元配列と等価になるのでしょうか? 試してみたら結果は確かにどちらも変わらなかったのですがよくわからないのでおしえていただきたいです
(*enemy)と、(*enemy)がどう違うかもよくわかりません
また、無駄にダブルポインタを使うのを止めるといいとありますが、構造体を値渡しすると容量が大きく、動作が遅くなる可能性あり、また、グローバル変数として扱うのもあまりよくないように感じます どうするべきなんでしょうかご教授いただけるとうれしいです。

また、肝心の動作のほうですが、はじめからフリーズすることは無くなりましたが、変数stege_countが119になるとフリーズしてしまいます
(おそらくみけCAT様のおっしゃるように確保していない領域に手を出していると思うのですが...)
いろいろ試してみたのですが、やはり期待通りの動作をしてくれないのでヒントをいただけるとうれしいです。

長々と質問してばっかりになってしまいました 本当に申し訳ありません

アバター
みけCAT
記事: 6246
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: プログラムが停止してしまう

#6

投稿記事 by みけCAT » 3年前

Iseuma14 さんが書きました:なぜダブルポインタが二次元配列と等価になるのでしょうか?
ダブルポインタは二次元配列と等価にはなりません

E1[E2]は*((E1)+(E2))と等価(N3337 5.2.1 Subscripting)なので、
enemy[0]は*((enemy)+(0))、すなわち*enemyと等価になります。
Iseuma14 さんが書きました:(*enemy)と、(*enemy)がどう違うかもよくわかりません

配列添字演算子[]は間接演算子*より優先順位が高いので、(*enemy)ではenemyが先に計算されます。
(*enemy)ではカッコがあるので、*enemyが先に計算されます。

Iseuma14 さんが書きました:また、無駄にダブルポインタを使うのを止めるといいとありますが、構造体を値渡しすると容量が大きく、動作が遅くなる可能性あり、また、グローバル変数として扱うのもあまりよくないように感じます どうするべきなんでしょうかご教授いただけるとうれしいです。

大きな構造体はあなたの言うとおり値渡ししないようにしましょう。
整数、実数、ポインタは、(現代の一般的と思われる環境では)ポインタと比べてサイズが多くても数倍程度しか違わないので、呼び出される側で呼び出す側のデータを書き換える必要が無ければ値渡ししましょう。

Iseuma14 さんが書きました:また、肝心の動作のほうですが、はじめからフリーズすることは無くなりましたが、変数stege_countが119になるとフリーズしてしまいます
(おそらくみけCAT様のおっしゃるように確保していない領域に手を出していると思うのですが...)
いろいろ試してみたのですが、やはり期待通りの動作をしてくれないのでヒントをいただけるとうれしいです。

初期化されていない自動変数(staticでないローカル変数)には不定の値が入っていることがあります。
変数は値を使用する前に初期化しましょう。
デバッガが使える場合は、使ってどこで詰んでいるのかを調べるのもいいかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Iseuma14
記事: 54
登録日時: 4年前

Re: プログラムが停止してしまう

#7

投稿記事 by Iseuma14 » 3年前

>>みけCAT様お返事ありがとうございます
非常にわかりやすい解説ありがとうございました
まだまだ素人の私には非常に勉強になる内容でした 特に、計算の優先順位はあまり意識してこなかったので意識を向けていこうと思いました

デバッガ使ってがんばります

閉鎖

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