こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C++デバックエラーについて詳しく教えてください。

Microsoft Visual C++ Debug Library
と言うエラーが発生しました。
Visual C++ 2008 Express Edition を使っています。
状況は以下になります。

Program:C:\DxLib_VC\サンプルプログラム実行用フォルダ
\Debug\DxLib_VC2008用.exe
Module:C:\DxLib_VC\サンプルプログラム実行用フォルダ
\Debug\DxLib_VC2008用.exe
File:
Run-Time Check Failure #3 - The variable 'temp' is being used
without being initialized
(Press Retry to debug the application)

Run-Timeの部分から自分なりに調べてみたのですが
ランタイム・チェック失敗#3-変数'temp'は初期化されずに使用されています
と書いてあると思います。
それで
いろいろみなさんに意見をいただいたのですが
stype!=0のときの処理が書けません。
初期化は出来たのですが、複数の敵が弾をだすはずが
プレイヤーしかでなくなりました。
またいろいろ意見お願いします。

tempの部分のコードは以下です。

(define.h)
struct E_SHOT{
bool flag;//弾が発射中かどうか
double x;//x座標
double y;//y座標
int gh;//グラフィックハンドル
int width,height;//画像の幅と高さ
int pattern;//ショットパターン
int speed;//弾スピード
};
#define ENEMY_SNUM 50//敵の弾の上限

(enemy.cpp)
#include "pch.h"
#include "enemy.h"

ENEMY::ENEMY(
int type,//敵タイプ、
int stype,//弾種類
int m_pattern,//移動パターン、
int s_pattern,//発射パターン
int in_time,//出現時間、
int stop_time,//停止時間、
int shot_time,//弾発射時間、
int out_time,//帰還時間、
int x,//x座標、
int y,//Y座標、
int speed,//弾スピード
int hp,//HP
int item//アイテム)

{

//サイズ
width=27;
height=25;
    
//敵の種類
this->type=type;

//弾の種類
this->stype=stype;

//移動パターンとショットパターン
this->m_pattern=m_pattern;
this->s_pattern=s_pattern;
    
this->speed=speed;

//座標セット
this->x=x;
this->y=y;

//出現、停止、発射、帰還セット
this->in_time=in_time;
this->stop_time=stop_time;
this->shot_time=shot_time;
this->out_time=out_time;

//hpとアイテム代入
this->hp=hp;
this->item=item;

//弾初期化
memset(shot,0,sizeof(shot));

//敵画像読み込み
if(type==0){
LoadDivGraph("enemy.png",3,1,3,27,25,gh);
}
int temp;
//弾画像読み込み
if(stype==0){
temp=LoadGraph("enemyshot1.png");
}

//サイズ取得
int w,h;
GetGraphSize(temp,&w,&h);
//弾の初期化
for(int i=0;i<ENEMY_SNUM;++i){
shot[i].flag=false;
shot[i].gh=temp;
shot[i].width=w;
shot[i].height=h;
shot[i].pattern=s_pattern;
shot[i].speed=speed;
shot[i].x=x;
shot[i].y=y;
}
count=0;
scount=0;

deadflag=false;
endflag=false;
sflag=false;
}

void ENEMY::Move()
{
//出てきてから止まる時間までの間なら下に移動
if(in_time<g_count && g_count<stop_time){
  y+=2;
    
//帰還時間を過ぎたら戻る。
}else if(g_count>out_time){
   y-=2;
   if(y<-40){
   deadflag=true;
 }
   }
}

void ENEMY::Draw()
{
int temp;

//弾から最初に描画
for(int i=0;i<ENEMY_SNUM;++i){
if(shot[i].flag){
DrawGraph(shot[i].x,shot[i].y,shot[i].gh,true);
}
}


if(!deadflag){

temp= count%40/10;
if(temp==3)
temp=1;
DrawGraph(x,y,gh[temp],TRUE);
}
}

bool ENEMY::All()
{
Move();

Shot();

Draw();

++count;

return endflag;
}

void ENEMY::Shot()
{

//発射タイミングになったら、フラグを立てる
if(shot_time==g_count){
   sflag=true;
   }

//フラグを立てるときだけ
if(sflag){

  switch(s_pattern){
case 0:
//10回に一回発射。40までなので5発発射。
if(scount%10==0 && scount<=40){
for(int i=0;i<ENEMY_SNUM;++i){
//フラグが立ってない弾を探して、座標をセット
if(shot[i].flag==false){
  shot[i].flag=true;
shot[i].x=x;
shot[i].y=y;
break;
}
}
}
break;
}


//フラグが立ってる弾の数
int s=0;

//フラグが立ってる弾だけ、弾の移動を行う
for(int i=0;i<ENEMY_SNUM;++i){
if(shot[i].flag){
shot[i].y+=shot[i].speed;

//弾が画面をはみ出たらフラグを戻す。
if(shot[i].x<-20 || shot[i].x>420
|| shot[i].y<-20 || shot[i].y>500){
shot[i].flag=false;
continue;
}
++s;
}
}
//sがゼロということは発射中の弾がない。
//かつdeadflagがTRUEということはこの敵のクラスは消滅させてよい
if(s==0 && deadflag){
//敵クラス消滅フラグをTRUEにする
endflag=true;
}

++scount;

}

}

投稿日時 - 2014-02-03 20:43:24

QNo.8460028

すぐに回答ほしいです

質問者が選んだベストアンサー

現状の理解状態から推察するに…先は長そうですねぇ……。

>あとゴミが残っているとはどういう内容か知りたいです。

未初期化のローカル変数がどうなっているのか?
ということを勉強してくださいな。

>データーはエクセルの一つのセルに1個ずつ

CSV出力した時にどういう形式になっているのか理解しています?
というか、出力したCSVをテキストエディタで眺めたことはありますか??

読み込み処理の部分、デバッガのステップ実行で1つずつ追いかけて、
・期待する動作はどんなものだったのか
・実際の動作はどうなのか
を確認した方がいいでしょう。

http://marupeke296.com/DBG_No1_Step.html
http://www.atmarkit.co.jp/fdotnet/chushin/vsdebug_01/vsdebug_01_02.html
http://www.a.math.ryukoku.ac.jp/~hig/guide/vs2008/debugger.php
http://visualstudiostudy.blog.fc2.com/blog-entry-9.html
http://news.mynavi.jp/articles/2008/08/18/debug/
などなど……

投稿日時 - 2014-02-14 09:20:42

お礼

お疲れ様です。

理解不足ですいません。

CSV出力した時にどういう形式になっているのか理解しています?

いいえ

出力したCSVをテキストエディタで眺めたことはありますか??

いいえ

サイトを確認しながら先が長くならないように努力します。
ありがとうございました。
失礼します。

投稿日時 - 2014-02-14 11:27:08

ANo.13

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(13)

ANo.12

本当にそのようなデータなのですか?

データは, 本当に「1行に 1個ずつ書かれている」のですか?

自分のコードがどのようなデータを期待しているか, 理解できていますか?

投稿日時 - 2014-02-14 01:24:35

お礼

お疲れ様です。

データーはエクセルの一つのセルに1個ずつ
書かれています。

自分のコードがどのようなデータを期待しているか, 理解できていますか?
について

敵キャラ5匹分の
敵の種類、弾の種類、移動パターン、発射パターン、出現時間、停止、
発射、帰還、X座標、Y座標、弾スピード、HP、アイテムの値を
読み込み出力することです。

いつも丁寧にありがとございます。
失礼します。

投稿日時 - 2014-02-14 03:09:42

ANo.11

Wr5

>全員が全員意図的に無視しているような感じがしてきた

意図的に無視していたわけでもなく、たいして気にしていなかった……。
が、まぁ、データ形式が微妙ですね。
# 掲示しているコードだと列と行が入れ替わっていることになりますし……。

意図した状態にデータを切り出せているのか…は自前で確認してもらいたいところ。
# なんか、だんだん当初の問題から離れていっているなぁ…。

投稿日時 - 2014-02-06 17:15:34

お礼

いつもありがとございます。
まだ解決はしていないですがいろいろまとめながら
前に進み解決したいと思います。

失礼します。

投稿日時 - 2014-02-13 23:18:38

ANo.10

全員が全員意図的に無視しているような感じがしてきたのですが, 読み込ませているデータは本当に
---------- ここから ----------
敵の種類 0 0 0 0 0
弾の種類 0 0 0 0 0
移動パタターン0 0 0 0 0
発射パターン 0 0 0 0 0
出現時間60 120 180 240 300
停止 120 180 240 300 360
発射 121 181 241 301 361
帰還 300 340 400 460 520
X座標 50 100 150 200 250
Y座標 -40 -40 -40 -40 -40
弾のスピード 4 4 4 4 4
HP 1 1 1 1 1
アイテム 0 0 0 0 0
---------- ここまで ----------
という形式なんですか? もしそうだとしたら, 途中にカンマが出てこないから 1行丸ごと読み込んじゃいますよ. つまり, type 以外には何も読み込まないから, stype にはゴミが残ったままです.

データの形式が上の様ではないというなら, あなたが #3 への「お礼」に書いた「エクセル内容」は何の役にも立ちません. そんなクズを見せるのは「時間と労力の無駄」でしかないので, そんなことをするくらいなら (最初の数行でいいので) 実際のデータを出してください.

投稿日時 - 2014-02-06 12:45:17

お礼

いつもありがとうございます。
形式の部分ですが実は
敵の種類
0
0
0
0
0
と1セルごとに中に記述してあります。(以下省略)
この形式でもカンマは必要ですか。
あとゴミが残っているとはどういう内容か知りたいです。
いろいろ勉強不足ですいません。

また見かけたらよろしくお願いします。

投稿日時 - 2014-02-13 23:13:46

ANo.9

Wr5

fgetc()で1文字ずつ読み込んで~とか処理しているから変に見えるんじゃないですかねぇ……。
Cランタイム使うならfgets()で1行まるっと読み込んで、CSVをパースする方がいいのではないかと。
# CSVをパースする処理自体はよくあるパターンなので、検索すればいろいろ見つかるでしょう。
# 「CSV C言語 読み込み」辺りで探せばそれなりに見つかるはずです。
# エラー処理簡略化するならstrtok()でぶった切ってもいいでしょうし。(strtok()でcsvを読み込む場合の問題点も検索すれば出てくるでしょうし)

読み込み処理自体もwhile(1)の無限ループとgotoでの脱出というのが違和感醸し出す元かと思われます。

>case 2: data[row].stype=atoi(buf); break;
のところでdata[row].stypeが0以外の値になったらbufの内容を確認する。
みたいなコードを埋め込めば、とりあえずの原因は探せるかもしれません。

私なら…読み込み中のcsvファイルの行数をカウントするようにして、
case 2:
 data[row].stype=atoi(buf);
 if(data[row].stype != 0) {
  int a = 0;
 }
 break;
でint a = 0;にブレークポイントを設定する…とかしますかね。
# TRACE()マクロとかOutputDebugString()を使うこともある。

投稿日時 - 2014-02-06 09:37:24

お礼

いつもありがとございます。

まだ解決はしていないですがいろいろ検索しながら
他の方法も勉強しながら理解を深め解決したいと
思います。

また見かけたらよろしくお願いします。

投稿日時 - 2014-02-13 23:23:08

ANo.8

> throw "Unknown stype\n"; でためさせてもらいました。
> そしたら以下のエラーが出てしまいました。
#4のコードは「stype==0じゃなかったらエラー発生とみなす」というコードです。
つまり、「エラーが出た」ということは「stype!=0になっているENEMYがいる」ということです。
(#7でも指摘されていますが)

ファイルの読み込み部分を確認し、本当に意図通りに読み込めているかをチェックしてください。

投稿日時 - 2014-02-06 08:31:49

お礼

いつもありがとうございます。

throw "Unknown stype\n"; については
勉強不足ですいません。

ファイルの読み込み部分でまだいきずまっていますが
まとめながら進みたいと思います。

失礼します。

投稿日時 - 2014-02-13 23:28:29

ANo.7

それはつまり
stype == 0 を満たさないやつがいる
ってことじゃないか? データをきちんと読み込めているかどうか, 確認した?

あと #6 についていえば「単に 1文字ずつつなげる」だけなんだから strcat なんか使うことはない. 例えば
char *buf_ptr;
を用意し, memset のところを
buf_ptr = buf;
として strcat を呼び出す代わりに
*buf_ptr++ = c;
とする. そして, // ここにきたということは の次の switch の前で
*buf_ptr = '\0';
とすればいい... あれ? なんか読み込み部分にすごい違和感がある....

投稿日時 - 2014-02-06 02:33:12

お礼

いつもありがとうございます。

いろいろ勉強になります。
がんばります。
失礼します。

投稿日時 - 2014-02-13 23:32:12

ANo.6

あ, 処理系が書いてあるのを見落としてた. バッファオーバーラン以外のバグはないな. ごめんなさい.

とはいえ非常に不思議な書き方ではある. なぜに strcat?

投稿日時 - 2014-02-05 16:01:13

お礼

Tacosanさん投稿していただきありがとうございます。
初心者な分知識が薄いためみなさんのいろんな言葉が
勉強になり気になることばかりでプログラムの好きな
自分にとってはたのしいことばかりです。
strcat?の理由もすごく気になります。知りたいです。
バッファオーバーランについても知識が薄いため
自分なりにも勉強して理解をするようにします。
みなさんのように回答できるようになりたいです。
失礼します。

投稿日時 - 2014-02-06 01:27:04

ANo.5

本題ではありませんが....

#3 への「お礼」にあるプログラムにはバグが潜んでいます. 認識できていますか?

投稿日時 - 2014-02-05 11:15:32

ANo.4

> 今の段階でstypeは0以外ありえないという意味です
ということなら、今の段階では「stypeに0以外の数字が入っているのは想定外だからエラー」という風にしておけばいいのでは?

//弾画像読み込み
if(stype==0){
 temp=LoadGraph("enemyshot1.png");
}else{
 //stype!=0なのは想定外
 throw "Unknown stype\n"; //例外にするなり、とりあえずstype==0のときと同様にして続行するなり、ご自由にどうぞ
}

投稿日時 - 2014-02-05 09:20:04

お礼

Picosoftさんお疲れ様です。
いつも感謝します。
throw "Unknown stype\n"; でためさせてもらいました。
そしたら以下のエラーが出てしまいました。
でも、throwやRuntime Error!についても理解が薄いので
勉強しながら頑張りたいと思います。
ありがとうございました。
失礼します。

Microsoft Visual C++ Runtime Library
Runtime Error!
Program:
This application has requested the Runtime to terminate it in an unusual way
Please contact the application's support team for more information.

(たぶんこんな感じのことがかいてあるとおもうのですが)
この適用は、異常な方法でそれを終了することをランタイムに要求しました。
詳細については適用のサポート・チームと連絡をとってください。

投稿日時 - 2014-02-06 01:06:03

ANo.3

「今の段階では弾は一種類だけ」ということは「今の段階でstypeは0以外ありえない」という意味ですよね?
どこかにstypeに0以外を指定しているENEMYはないですか?

投稿日時 - 2014-02-04 12:13:11

お礼

Picosoftさんいつもありがとうございます。
今の段階でstypeは0以外ありえないという意味です

stypeに0以外を指定しているENEMYについては
switch文の部分でこのように指定している部分が

case 2: data[row].stype=atoi(buf); break;

だけです。
それでswitch文のコードの最後で敵クラスの生成をしています。
全体のコードでstypeに0以外を指定しているような部分は
これだけです。

それでcontrol.cppですべてのクラスを操作しています
今回はcontrol.cppで
外部データ(エクセル)を読み込んで、
それを変数に入るようにしています。
それが下記にもあるこれです

fp = fopen("enemydata.csv","r");

このエクセル内容が(敵キャラ五匹分です)
敵の種類 0 0 0 0 0
弾の種類 0 0 0 0 0
移動パタターン0 0 0 0 0
発射パターン 0 0 0 0 0
出現時間60 120 180 240 300
停止 120 180 240 300 360
発射 121 181 241 301 361
帰還 300 340 400 460 520
X座標 50 100 150 200 250
Y座標 -40 -40 -40 -40 -40
弾のスピード 4 4 4 4 4
HP 1 1 1 1 1
アイテム 0 0 0 0 0
です。

コードは
control.cpp
control.h
enemy.h
define.hは前回載せていなかった
ENEMYDATAの部分をのせました。
前回と今回のでENEMY関係はこれで全部です。
失礼します。

(control.cpp)
#include "pch.h"
#include "control.h"
#include <stdio.h>
CONTROL::CONTROL()
{
player = new PLAYER;
back = new BACK;
FILE *fp;
ENEMYDATA data[ENEMY_NUM];
char buf[100];
int c;
int col=1;
int row=0;
memset(buf,0,sizeof(buf));
fp = fopen("enemydata.csv","r");
//ヘッダ読み飛ばし
while(fgetc(fp)!='\n');
while(1){
while(1){
c=fgetc(fp);
//末尾ならループを抜ける。
if(c==EOF)
goto out;
//カンマか改行でなければ、文字としてつなげる
if(c!=','&& c!='\n')
strcat(buf,(const char*)&c);
//カンマか改行ならループ抜ける。
else
break;
}
//ここにきたということは、1セル分の文字列が出来上がったということ
switch(col){
//1列目は敵種類を表す。atoi関数で数値として代入。
case 1: data[row].type=atoi(buf); break;
//2列目は弾種類。以降省略。
case 2: data[row].stype=atoi(buf); break;
case 3: data[row].m_pattern=atoi(buf); break;
case 4: data[row].s_pattern=atoi(buf); break;
case 5: data[row].in_time=atoi(buf); break;
case 6: data[row].stop_time=atoi(buf); break;
case 7: data[row].shot_time=atoi(buf); break;
case 8: data[row].out_time=atoi(buf); break;
case 9: data[row].x=atoi(buf); break;
case 10: data[row].y=atoi(buf); break;
case 11: data[row].speed=atoi(buf); break;
case 12: data[row].hp=atoi(buf); break;
case 13: data[row].item=atoi(buf); break;
}
//バッファを初期化
memset(buf,0,sizeof(buf));
//列数を足す
++col;
//もし読み込んだ文字が改行だったら列数を初期化して行数を増やす
if(c=='\n'){
col=1;
++row;
}
}
out:
//敵クラス生成
for(int i=0;i<ENEMY_NUM;++i){
enemy[i]=new ENEMY(
data[i].type,
data[i].stype,
data[i].m_pattern,
data[i].s_pattern,
data[i].in_time,
data[i].stop_time,
data[i].shot_time,
data[i].out_time,
data[i].x,
data[i].y,
data[i].speed,
data[i].hp,
data[i].item);
}
}
void CONTROL::All()
{
//int count = 0;
//描画領域を指定
SetDrawArea(MARGIN,MARGIN,MARGIN+380,MARGIN+460);
back->All();
//プレイヤークラスのAll関数実行
player->All();
for(int i=0;i<ENEMY_NUM;++i){
if(enemy[i]!=NULL){
if(enemy[i]->All()){
delete enemy[i];
enemy[i]=NULL;
}
}
}
++g_count;
}
CONTROL::~CONTROL()
{
//プレイヤークラスの解放
delete player;
delete back;
for(int i=0;i<ENEMY_NUM;++i){
if(enemy[i]!=0){
delete enemy[i];
}
}
}


(control.h)
#include "player.h"
#include "back.h"
#include "enemy.h"
class CONTROL
{
private:
double y;
private:
//プレイヤークラスのポインタ
PLAYER *player;
//背景クラス
BACK *back;
ENEMY *enemy[ENEMY_NUM];
public:
CONTROL();
CONTROL();
void All();
};


(enemy.h)
#include "pch.h"
class ENEMY
{
private:
//座標とグラフィックハンドル
double x,y;
int gh[3];
//画像サイズ
int width,height;
//出現、停止、帰還、発射タイミング
int in_time,stop_time,out_time,shot_time;
//敵の種類
int type;
//弾の種類
int stype;
//移動パターン
int m_pattern;
//ショットパターン
int s_pattern;
//弾スピード
int speed;
int hp;
int item;
//敵が出現してからのカウント
int count;
//敵消滅フラグ
bool deadflag;
//敵クラス消滅フラグ
bool endflag;
//弾の構造体
E_SHOT shot[ENEMY_SNUM];
//ショットが撃てるようになったかのフラグ
bool sflag;
//ショットが撃てるようになってからのカウント
int scount;
//関数関係
public:
bool All();
void Move();
void Shot();
void Draw();
ENEMY(
int type,//敵タイプ、
int stype,//弾種類
int m_pattern,//移動パターン、
int s_pattern,//発射パターン
int in_time,//出現時間、
int stop_time,//停止時間、
int shot_time,//弾発射時間、
int out_time,//帰還時間、
int x,//x座標、
int y,//Y座標、
int speed,//弾スピード
int hp,//HP
int item//アイテム
);
};


(define.h)
struct ENEMYDATA{
int type;//敵種類
int stype;//弾種類
int m_pattern;//移動パターン
int s_pattern;//発射パターン
int in_time;//出現時間
int stop_time;//停止時間
int shot_time;//弾発射時間
int out_time;//帰還時間
int x;//x座標
int y;//y座標
int speed;//弾スピード
int hp;//HP
int item;//アイテム
};
#define ENEMY_NUM 5//敵の数

投稿日時 - 2014-02-05 00:30:29

ANo.2

Wr5

細かくソース読む気もありませんが……
まぁ、すでに回答されている内容で十分…でしょうな。

というか、変数名tempってのが判りにくいってのもありますかねぇ。
もう少し意味のある名前をつけるように工夫した方がいいかと思いますよ。
# まぁ、私も~Tempとかの変数名はよく使いますけどね。

投稿日時 - 2014-02-03 23:54:28

お礼

自分でも工夫できるように努力します。

投稿日時 - 2014-02-04 01:11:51

ANo.1

> いろいろみなさんに意見をいただいたのですが
> stype!=0のときの処理が書けません。
> 初期化は出来たのですが、複数の敵が弾をだすはずが
> プレイヤーしかでなくなりました。
> またいろいろ意見お願いします。
んなもん知らんよ。

……と言うのが結論ですが、なぜそう言わないとならないかを以下に説明します。

今回問題になっているのはコンストラクタの以下のコードです。
> int temp;
> //弾画像読み込み
> if(stype==0){
> temp=LoadGraph("enemyshot1.png");
> }
ここで stype が何なのかを見てみるとコンストラクタの引数の
> int stype,//弾種類
だとわかります。つまり、問題のコードを日本語に書き直すと、
 (弾の画像のハンドルを格納する) temp という変数を用意する。
 もし弾種類が 0 ならば enemyshot1.png という画像を読み込んでそのハンドルの値を temp に格納する。
となります。

では弾種類が 0 でない、たとえば 1 の場合どんな画像を弾の画像として読み込めばいいのか?
これはあなたにしかわかりませんし、そもそも弾が何種類あるのか、弾種類が想定する値以外の値が stype に入ってきたときにどんな画像にするのか、それともエラーとするのかについては、あなた自身が決定しなくてはならない問題です。
そのような問題について質問されても、された側としては「んなもん知らんよ」としか答えようがありません。

繰り返しますが、弾種類が 0 でない場合どんな画像を弾の画像として読み込めばいいのかは「あなた」が決定しなくてはならないことです。それを決めてきたなら答えようがありますので決めてください。

投稿日時 - 2014-02-03 22:23:46

お礼

お疲れ様です。
意見ありがとうございます。
今、サイトのサンプルを勉強しているかぎりでは
弾種類と定義しているだけで
今の段階では弾は一種類だけで
このサンプルの現段階の題名が
複数の敵を表示しようで
五匹の敵が出てきてどの敵も同じ弾を撃つところまでで
弾を増やす見たいな課題はもう少し先の課題になっていて
いろいろ理屈はわかっていてもいざコードにしようとすると書けなく
こんがらがっていますが、がんばります。
失礼します。

投稿日時 - 2014-02-04 03:03:20