突然のExceptionエラー

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
rozeo
記事: 86
登録日時: 12年前
住所: 広島 呉 (学生寮
連絡を取る:

突然のExceptionエラー

#1

投稿記事 by rozeo » 11年前

こんにちは、rozeoです。

DXライブラリでプログラムを作って実行したところ以下のエラーダイアログが表示されました。

Debug Assertion Failed!

Program:...Documents/Visual Studio 2010/Projects/TankPlace/TankPlace.exe
File: f:/dd\vctools\crt_bld\self_x86\crt\src\dbgheap.c
Line: 1322

Exception: _CtrIsValidHeapPointer(pUserData)

For infomation on your program can cause an assertion
failure,see the Visual C++ documentation on asserts.

(Press Retry to debug applcation)

一応自分で解釈してみたところ、VC関連のファイル、dbgheap.cのヒープという部分(?)壊れているらしいです。

このヒープとはいったいなんでしょうか?
またこのエラーの原因と考えられることとはいったいなんでしょうか?
また解決するにはどのようにコードを改変すればいいでしょうか?

ご鞭撻よろしくお願いします。

rozeo
記事: 86
登録日時: 12年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: 突然のExceptionエラー

#2

投稿記事 by rozeo » 11年前

追記

wikipediaではヒープ(領域)に関して以下のように説明されていました。

ヒープ領域(ヒープりょういき)とはコンピュータープログラミングにおいて、動的に確保可能なメモリの領域。ヒープ (heap) とは、『山積み』という言葉の中の『山』をさす英単語である。データ構造のヒープとは直接的な関係は無い。

ヒープ領域は、2種類のラベルを持つ双方向リストによって構成されている。初期状態では、リストはひとつの「未使用」ノードが全体を占めていて、メモリ確保関数(C言語のmalloc, C++のnew等)によって、「未使用」ノードから必要な分を切り取って「使用中」ノードと「未使用」ノードに分ける。確保したメモリが不要になった場合には、メモリ解放関数(C言語のfree, C++のdelete等)によってノードのラベルを「未使用」に書き換える。解放のつど、あるいはカウンタによって一定水準に達した時、連続した個々の「未使用」ノードが結合され、大きな「未使用」ノードに還元される。「未使用」ノードが不足した場合には、オペレーティングシステムに領域拡大を要求し、ヒープ領域が拡大される。 ヒープ領域により、変数領域を動的に確保できる利点があるが、領域の確保と解放の繰り返しによりヒープ上にどこからも参照されない領域が発生することがある。この領域をガベージ(ゴミ)という。 「未使用ノード」と「使用中」ノードが混在、つまりガベージによりヒープ領域がバラバラに分断された状態をフラグメンテーション状態と呼ぶ。

プログラム中にfreeは使いましたがfreeを使っコンパイルした時にはエラーは発生しませんでした。
またコンパイルエラーやワーニングは出ませんでした。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 突然のExceptionエラー

#3

投稿記事 by h2so5 » 11年前

ヒープ破壊はコンパイル時には検出できません。実行してはじめてエラーが発生します。
配列の範囲外アクセスや、無効なポインタ(freeしたあとのアドレス)への書き込みなどを行うとヒープが破壊されます。

具体的にどこが問題なのかはソースコードを見ないと分かりません。

アバター
usao
記事: 1889
登録日時: 12年前
連絡を取る:

Re: 突然のExceptionエラー

#4

投稿記事 by usao » 11年前

Debugビルドして動かしても同じ状況が出るのであれば
ステップ実行等で,どの時点で例外発生しているのかを突き止めると良いでしょう.
例えば,「A()という関数を呼びだしたらそうなる」とかいうあたりまでわかれば
その関数に渡している引数の値を疑う等して,原因が究明できると思います.

Releaseだと出るけどDebugだと出ない とかいう状況だと
詳細な場所まで突き止めるのが難しくなるかもしれませんが,
それでも Releaseビルドしたものをデバッグ実行して ある程度範囲を絞りこめると思います.

rozeo
記事: 86
登録日時: 12年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: 突然のExceptionエラー

#5

投稿記事 by rozeo » 11年前

usao さんが書きました:Debugビルドして動かしても同じ状況が出るのであれば
ステップ実行等で,どの時点で例外発生しているのかを突き止めると良いでしょう.
例えば,「A()という関数を呼びだしたらそうなる」とかいうあたりまでわかれば
その関数に渡している引数の値を疑う等して,原因が究明できると思います.

Releaseだと出るけどDebugだと出ない とかいう状況だと
詳細な場所まで突き止めるのが難しくなるかもしれませんが,
それでも Releaseビルドしたものをデバッグ実行して ある程度範囲を絞りこめると思います.
ご返事ありがとうございます。詳細なエラー発生タイミングはメインループからでてDxLib_End()までの間です。その間にはメモリ開放としてfreeだったりを記述しています。その後ににはDxLib_end()しかありません。またfreeを書いて実行した辞典ではエラーは発生しませんでした。
ソースコードをのせます

コード:

//main.cpp
#include "Key.h"
#include "Define.h"

int programEndFlg = FLG_OFF;

extern void KeyCheckAll();
extern void Initialization();
extern void Menu();
extern void Destract();

int ProcessLoop(){
	if(ProcessMessage() != 0){
		return -1;
	}
	if(ClearDrawScreen() != 0){
		return -1;
	}
	KeyCheckAll();
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdShow,int nCmdLine){
	SetGraphMode(750,650,32);
	if(DxLib_Init() != 0 || SetDrawScreen(DX_SCREEN_BACK) != 0){
		return -1;
	}
	Initialization();
	while(ProcessLoop() == 0){
		Menu();
		if(CheckStateKey(KEY_INPUT_ESCAPE) != 0) break;
		if(programEndFlg == FLG_ON)              break;
		ScreenFlip();
	}
    Destract();
	DxLib_End();
	return 0;
}

コード:

//GraphHandle.h
extern int hMenuBack;
//ColorAndFontHandle.h
extern int hWhite,hBlack,hRime,hIndigo,hBlueGreen;
extern int font_ArialBlackSize16,font_ArialBlackSize32,font_ArialBlackSize64;

//Define.h
#include "DxLib.h"
#define FLG_OFF 0
#define FLG_ON  1

#define MENUTAG 5//メニュー項目数

#define COLORWHITE GetColor(255,255,255);//色作成マクロ 白
#define COLORBLACK GetColor(0  ,0  ,0  );//色作成マクロ 黒     

コード:

#include "Define.h"
#include "ColorAndFontHandle.h"
#include "GraphHandle.h"

char menuTag[MENUTAG][10] = {"newgame","continue","password","config","exit"};
int xPosSetting[MENUTAG]  = {5,0,0,50,70};//中央整頓用
int menuTagPosX[MENUTAG]  = {75,275,475,175,375};
int menuTagPosY[MENUTAG]  = {500,500,500,550,550};
int tagMove[MENUTAG]      = {1000,1200,1400,1100,1300};
int backStelseFlg         = FLG_ON;
int alpha                 = 0;
int menuStartActiveFlg    = FLG_ON;

void DrawMenu();
void MenuStart();

void Menu(){

	if(menuStartActiveFlg == FLG_ON) MenuStart();
	else                             DrawMenu();
}

void MenuStart(){
	if(backStelseFlg == FLG_ON){
		SetDrawBlendMode(DX_BLENDMODE_ALPHA,alpha);
		DrawGraph(0,0,hMenuBack,TRUE);
		SetDrawBlendMode(DX_BLENDMODE_NOBLEND,0);
		alpha +=3;
		if(alpha > 255){
			backStelseFlg = FLG_OFF;
		}
	}else if(backStelseFlg == FLG_OFF){
		DrawGraph(0,0,hMenuBack,TRUE);
		for(int i = 0;i < MENUTAG;i++){
			DrawStringToHandle(menuTagPosX[i]+xPosSetting[i],menuTagPosY[i],menuTag[i],
				               hBlueGreen,font_ArialBlackSize32);
		}
		for(int i = 0;i < MENUTAG;i++){
			tagMove[i] -=25;
		}
		if(tagMove[0] < 75){
			menuStartActiveFlg = FLG_OFF;
		}
	}
}
void DrawMenu(){
	DrawGraph(0,0,hMenuBack,TRUE);

	for(int i = 0;i < MENUTAG;i++){
		DrawStringToHandle(menuTagPosX[i]+xPosSetting[i],menuTagPosY[i],menuTag[i],
			               hBlueGreen,font_ArialBlackSize32);
	}
}

コード:

//Destract.cpp
#include "DxLib.h"
#include "ColorAndFontHandle.h"
#include "GraphHandle.h"

void Destract(){
	DeleteFontToHandle(font_ArialBlackSize16);
	DeleteFontToHandle(font_ArialBlackSize32);
	DeleteFontToHandle(font_ArialBlackSize64);
	InitGraph();

	free(&hMenuBack);
	free(&hWhite);
	free(&hBlack);
	free(&hRime);
	free(&hIndigo);
	free(&hBlueGreen);
}

コード:

//Initialization.cpp
#include "DxLib.h"

int font_ArialBlackSize32,font_ArialBlackSize64,font_ArialBlackSize16;
int hWhite,hBlack,hRime,hIndigo,hBlueGreen;

int hMenuBack;

void Initialization(){//変数、ハンドルなどの初期化

	//既存フォント[Arial Black]のサイズ16,32,64のフォントを作成
	font_ArialBlackSize16 = CreateFontToHandle("Arial Black",16,
		                                       DX_FONTTYPE_ANTIALIASING_EDGE_8X8);
	font_ArialBlackSize32 = CreateFontToHandle("Arial Black",32,
		                                       DX_FONTTYPE_ANTIALIASING_EDGE_8X8);
	font_ArialBlackSize64 = CreateFontToHandle("Arial Black",64,
		                                       DX_FONTTYPE_ANTIALIASING_EDGE_8X8);
	hWhite     = GetColor(255,255,255);//黒
    hBlack     = GetColor(0  ,0  ,0  );//白
	hRime      = GetColor(153,204,0  );//ライム
	hIndigo    = GetColor(51 ,51 ,153);//インディゴ
	hBlueGreen = GetColor(0  ,128,128);//青緑
	hMenuBack = LoadGraph("dat/MenuBack.png");
}

コード:

//Key.cpp
#include "DxLib.h"

int stateKey[256];

void KeyCheckAll(){

	char key[256];

	GetHitKeyStateAll(key);

	for(int i = 0;i < 256;i++){
		if(key[i] == 1) stateKey[i]++;
		else            stateKey[i] = 0;
	}
}

int CheckStateKey(unsigned char Handle){
	return stateKey[Handle];
}
あとこうするとかさばるのでスポイラーのやりかたを教えてほしいです。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: 突然のExceptionエラー

#6

投稿記事 by h2so5 » 11年前

freeしてよいのはmallocで確保した領域だけです。静的記憶領域をfreeしてはいけません。
このプログラムでは動的確保をしていないのでfreeは不要です。

スポイラーは
► スポイラーを表示

rozeo
記事: 86
登録日時: 12年前
住所: 広島 呉 (学生寮
連絡を取る:

Re: 突然のExceptionエラー

#7

投稿記事 by rozeo » 11年前

ありがとうございます。
Destract.cppのfree()のやつを全て消したらエラーが発生しました。
free関数の使い方を見誤ってました。

ご返答ありがとうございました。

閉鎖

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