アクセス違反が解決できません!

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

アクセス違反が解決できません!

#1

投稿記事 by ochaduke » 4年前

ご無沙汰しております。

現在c++でdxlibを用いて、「テキストファイルで指定されたサウンドを流す」というものを作っているのですが、(多分、)テキストファイルの内容を読み込んでそれをvectorクラスの動的配列に代入していく過程でアクセス違反が出てしまいます。
ブレークポイントを設定して調べてみたりしたのですが、エラーの吐き出されるタイミングがまちまちで、エラーの原因がどこにあるのかわかりません。
以下に、コードとエラー(数種類ある(※))を載せますので、原因と解決策をご指南ください。よろしくお願いします。
(※)1回のデバッグにつき1種類のエラーが吐き出されますが、何回かデバッグをしていると、全部で3種類ほどのエラーが出てることが分かりました。いずれも似たような内容のようです。ここでは、取得できた2種類のエラーを載せています。

環境は、Windows10,vs2015,dxlib,c++です。


コード↓

MAIN.cpp

コード:

#include<string>
#include"dxlib.h"
#include"Load.h"		//データのロード
#include"mainsystem.h"	//曲の情報、再生、ステータスを管理
//#include"ui.h"			//user interface


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) {

	//-----primary setting-----//
	using namespace std;
	ChangeWindowMode(TRUE);
	SetAlwaysRunFlag(TRUE);
	SetOutApplicationLogValidFlag(FALSE);
	SetGraphMode(640, 500, 16);
	SetWindowText("エラーから助けてください。お願いします。");
	SetWindowIconID(210);
	if (DxLib_Init() == -1) { return 0; }
	SetDrawScreen(DX_SCREEN_BACK);


	//*****起動*****//
	int screen_h = MakeScreen(400, 300, TRUE);		/タイトル描画用
	int title_h = LoadGraph(".\\graphs\\top_title.png");
	int titleback_h = LoadGraph(".\\graphs\\top_back.png");

//エフェクト用変数
	int x = 0;
	bool xturn = false;
	int flame = 0;
	int show = 300;

	int loadstatus = 0;
	int dates;	//曲の個数
	int missed_dates = 0;//ロードに失敗した項目の個数
	bool complete = false;

	LOAD* load;
	MSYS sys;
//	UI ui;

	load = new LOAD();

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && complete == false) {
		//-----タイトルなどの描画-----//
		/*back*/
		DrawGraph(0, 0, titleback_h, TRUE);

		/*title*/
		SetDrawScreen(screen_h);
		DrawGraph(0, 0, title_h, TRUE);
		
		/*effect*/
		GraphFilter(screen_h, DX_GRAPH_FILTER_HSB, 0, 0, x, x);

		SetDrawScreen(DX_SCREEN_BACK);
		DrawGraph(120, 60, screen_h, TRUE);


		//-----ファイルのロード処理-----//
		switch (loadstatus) {
		case 0:	//ここは1回しか通らない。
			DrawFormatString(150, 420, GetColor(0, 0, 0), "ファイルから項目を取得中...");

			/*項目の取得*/
			if (load->CheckFileDate() == -1) { break; }
			dates = load->SetDatesTotalNum();
			sys.SetArr(dates);//データを格納する配列の領域を確保
			break;

		case 1:	//データを代入
			load->SetFileDate(sys.PassIntDates("scene"), sys.PassIntDates("mode"), sys.PassStringDates("name"));
			missed_dates = load->LoadSound(sys.PassIntDates("sound_h"));
			break;

		case 2:	//ロードが完了した
			delete load;
			complete = true;
			break;

		case -1:	//ファイルや、ファイル内に項目が見つからなかった
			DrawFormatString(100, 420, GetColor(255, 0, 0), "ファイル、あるいは、データがありません。");

			//5秒間メッセージを表示して、その後終了させる。
			show--;
			if (show == 0) {
				delete load;
				return 0;
			}
			break;

		case -2:	//ロードに失敗したサウンドがある。
			DrawFormatString(150, 370, GetColor(175, 175, 175), "以下のファイルはロードに失敗しました。");
			load->ShowLoadError1();
			sys.GetMissedDatesSum(missed_dates);
			load -> ShowLoadError2(sys.PassStringDates("missedsound"));

			//5秒間表示させ、ロードを完了させる。
			show--;
			if (show == 0) { load->ShowLoadError1(true); }
			break;
			
		}

		//-----変数をいじる-----//
		loadstatus = load->SetLoadStatus();
		flame++;
		
		if (x == 0) { xturn = false; }
		else if (x == 100) { xturn = true; }
		
		if ((flame % 2) == 0 && xturn == false) { x+=2; }
		else if (flame % 2 == 0/* && xturn == true */) { x-=2; }
		
	}
	//*****起動終了*****//

	DxLib_End();
	return 0;
}

Load.h

コード:

#pragma once
#include<string>
#include<vector>
using namespace std;


class LOAD{
	
public:
	LOAD();
	int SetLoadStatus(void);//ロードの過程を示す
	int CheckFileDate(void);//ファイルを読み込む
	int SetDatesTotalNum(void);//項目数を提示->配列の確保に使用
	void SetFileDate(int* scene, int* mode, string* name);//確保された配列に代入。
	int LoadSound(int* sound_h);//サウンドを読み込み、確保された配列へハンドルを渡す。
	void ShowLoadError1(bool close = false);	//エラーの項目を見せる(引数trueでセクションを終了)
	void ShowLoadError2(string* missedsound);	//エラーの項目をMSYSクラスに渡す。
	
private:
	int loadstatus;			//ロードの進行
	int dates_counter;		//項目数-1
	vector<string>name_r;	//サウンドファイルの名前
	vector<int>scene_r;		
	vector<int>mode_r;		//再生の方法
	vector<int>errornum;	//ロードエラーの項目の番号
};

Load.cpp

コード:

#include"Dxlib.h"
#include"Load.h"
#include<vector>
#include<string>
#include<stdlib.h>

using namespace std;


LOAD::LOAD(){
	loadstatus = 0;
	dates_counter = -1;
}


int LOAD::SetLoadStatus(){
	return loadstatus;
}


int LOAD::CheckFileDate(){
	int FileHandle;
	
	FileHandle = FileRead_open( "SOUND LIST.txt" ) ;
	
	if(FileHandle == -1){
		loadstatus = -1;
		return -1;	
	}
	
	//-----読み込み-----//
	char scenebuff[2];
	int scene_w;
	char modebuff[2];
	int mode_w;
	char namebuff[50];

	//データのある71バイト目に移動
	FileRead_seek(FileHandle, 70, SEEK_SET);

	if(FileRead_eof(FileHandle) != 0){
		loadstatus = -1;
		return -1;
	}
	
	while(FileRead_eof(FileHandle) == 0){
		/*scene*/
		FileRead_read(&scenebuff, 1, FileHandle);
		scene_w = strtol(scenebuff, NULL, 10);
		scene_r.push_back(scene_w);
		FileRead_seek(FileHandle, 1, SEEK_CUR);
		
		/*mode*/
		FileRead_read(&modebuff, 1, FileHandle);
		mode_w = strtol(modebuff, NULL, 10);
		mode_r.push_back(mode_w);
		FileRead_seek(FileHandle, 1, SEEK_CUR);

		/*name*/
		FileRead_gets(namebuff, 50, FileHandle);
		name_r.push_back(namebuff);
		dates_counter++;
	}

	if (FileRead_close(FileHandle) == -1) {
		return -1;
	}
	
	
	//完了したら
	loadstatus = 1;
	return 0;
}


int LOAD::SetDatesTotalNum(void){
	if (dates_counter < 0) {
		return 0;
	}
	else { return dates_counter; }
}


void LOAD::SetFileDate(int* scene, int* mode, string* name){
	for(int i = 0; i <= dates_counter; i++){
		name[i] = name_r[i];
		mode[i] = mode_r[i];
		scene[i] = scene_r[i];
	}
}


int LOAD::LoadSound(int* sound_h){
	string filepath = ".\\sounds\\";
	string* fullpath;
	bool issamename = false;
	int process;	//非同期読み込み中のファイル数
	fullpath = new string[dates_counter];
	
	for(int i = 0; i <= dates_counter; i++){
		fullpath[i] = filepath + name_r[i];
	}
	
	//-----ハンドルゲット-----//
	SetUseASyncLoadFlag(TRUE);
	
	for(int i = 0; i <= dates_counter; i++){
		
		/*重複をさがす*/
		for(int j = i - 1; j >= 0; j--){
			if(fullpath[i] == fullpath[j]){
				sound_h[i] = sound_h[j];
				issamename = true;
				break;
			}
		}
		/*新しい項目なら読み込む*/
		if(!issamename){
			sound_h[i] = LoadSoundMem(fullpath[i].c_str());
		}
	}
	
	/*進捗を表示*/
	process = GetASyncLoadNum();
	DrawFormatString(100, 400, GetColor(100 + (process * 2), 200, 200), "...%2d / %d", process, (dates_counter + 1));
	
	
	/*完了したら*/
	if(process == 0){
		loadstatus = 2;
		delete[] fullpath;
	
		/*エラー走査*/
		for(int i = 0; i <= dates_counter; i++){
			if(sound_h[i] == -1){
				errornum.push_back(i);
				loadstatus = -2;
			}
		}
		
	}
	
	return errornum.size();
	
}


void LOAD::ShowLoadError1(bool close){

	DrawFormatString(40,390,GetColor(200,200,200),"TOTAL:%d",errornum.size());
	
	for(unsigned i = 0; i <= errornum.size(); i++){
		DrawFormatString(140,390+(i*20),GetColor(255,0,0),"%s",name_r[errornum[i]].c_str());
	}
	
	if(close){
		//completed
		loadstatus = 2;
	}
}

	
void LOAD::ShowLoadError2(string* missedsound){

	for(unsigned i = 0; i <= errornum.size(); i++){
		missedsound[i] = ".\\sounds\\" + name_r[i];
	}
	
}

mainsystem.h

コード:

class MSYS{
public:
MSYS();
~MSYS();

/*collect dates*/
void SetArr(int arr_length);//このクラスで重宝する配列を確保。
string* PassStringDates(string variablename);//要求されたstring型の配列の参照を返す
int* PassIntDates(string variablename);//要求されたint型の配列の参照を返す

void GetMissedDatesSum(int num);

/*handles and a player*/


/*Pass dates to UI class*/


private:
int* scene;
string* name;
int* mode;
int* sound_h;
string* missedsound;
bool ismissed;

};


mainsystem.cpp

コード:

#include<string>
#include"DxLib.h"
#include"mainsystem.h"
using namespace std;


MSYS::MSYS(){
	ismissed = false;
}


MSYS::~MSYS(){
	delete[] scene;
	delete[] name;
	delete[] mode;
	delete[] sound_h;
	if(ismissed){ delete[] missedsound; }
}

void MSYS::SetArr(int arr_length){
	scene = new int[arr_length];
	name = new string[arr_length];
	mode = new int[arr_length];
	sound_h = new int[arr_length];
}

string* MSYS::PassStringDates(string variablename){
	string error[1] = {"error"};

	if(variablename == "name"){
		return name;
	}
	else if(variablename == "missedsound"){
		return missedsound;
	}
	else{
		return error;//もはや使わないけど間に合わせ
	}
}


int* MSYS::PassIntDates(string variablename){
	int error = -1;

	if(variablename == "scene"){
		return scene;
	}
	else if(variablename == "mode"){
		return mode;
	}
	else if(variablename == "sound_h"){
		return sound_h;
	}
	else{
		return &error;//もはや使わないけど間に合わせ
	}
}



void MSYS::GetMissedDatesSum(int num){
	ismissed = true;
	missedsound = new string[num];
}


また、次のエラーが出ました。
~その1~
File:c:(中略)\vc\include\xmemory0
Line:106
Expression:"(_Ptr_user&(_BIG_ALLOCATION_ALIGNMENT -1))==0"&&0

~その2~
(前略)アクセス違反が発生しました

コード:

//mwmcpy.asm
CopyUpDwordLoop:
        mov     edx, dword ptr [esi]
        mov     dword ptr [edi], edx//ココらしい
        add     edi, 4
        add     esi, 4
        sub     ecx, 1
        jne     CopyUpDwordLoop



不足した情報があれば、お知らせください。
どうぞ、よろしくお願いします。
電車グ人生…

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

Re: アクセス違反が解決できません!

#2

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

ざっと見たところ、大量のoff-by-oneエラーがありますね。

コード:

string* hoge = new string[10];
vector<int> fuga;

// fugaに何らかの要素を挿入

string foo = hoge[10]; // ダメ
int bar = fuga[fuga.size()]; // ダメ
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: アクセス違反が解決できません!

#3

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

MSYS::PassStringDates関数やMSYS::PassIntDates関数はstaticでないローカル変数へのポインタを返していますが、これもいけません。
staticでないローカル変数はそのスコープを抜けると消え、それらを指しているポインタは無効な領域を指すことになります。
呼び出し側からは返されたポインタが有効か無効かわからないまま使い、無効なポインタをデリファレンスしてしまうリスクがあります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

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

Re: アクセス違反が解決できません!

#4

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

LOAD::LoadSound関数ではprocess == 0のときだけfullpath(が指している領域)を開放していますが、非同期読み込みなのですぐに読み込みが終わるとは限らず、メモリリークが発生する可能性があります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

ochaduke
記事: 36
登録日時: 4年前

Re: アクセス違反が解決できません!

#5

投稿記事 by ochaduke » 4年前

みけCATさん、素早い返信ありがとうございます。

自分でも唖然とするようなミスで、恥ずかしいばかりです。
ループの条件を見直して、適切な形にしたところ、しっかり動くようになりました。
ありがとうございました。

続いて、ご指摘いただいた部分も直していきたいと思います。
電車グ人生…

ochaduke
記事: 36
登録日時: 4年前

Re: アクセス違反が解決できません!

#6

投稿記事 by ochaduke » 4年前

自分の期待通りに動かすことができました。
勉強になりました。ありがとうございます。
電車グ人生…

閉鎖

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