ページ 11

リードエラーと出てきます。。

Posted: 2010年11月10日(水) 21:09
by MATTARI
龍神録プログラミングの館を参考にしています。
load_story()を読み込んだら、1面のボスを倒した後に2面へ、その次は3面へ…という風に自動でやっていきたいのですが、以下の変更ではコンパイルエラーは無くてもゲームの中でリードエラーと出て、csvファイルを読み込んでくれませんでした。

//敵の出現情報をエクセルから読み込んで格納する関数
void load_story(){
int n,num,i,fp,a=1;
char fname[32];
switch(a){
case 1:{
char fname[32]={"../dat/csv/storyH1.csv"};
if(boss.knd==boss.danmaku_num[1])
a=2;
        }
case 2:{
char fname[32]={"../dat/csv/storyH2.csv"};
if(boss.knd==boss.danmaku_num[1])
a=3;
        }
}


int input[64];
char inputc[64];

fp = FileRead_open(fname);//ファイル読み込み
if(fp == NULL){
printfDx("read error\n");
return;
}
for(i=0;i<2;i++)//最初の2行読み飛ばす
while(FileRead_getc(fp)!='\n');

n=0 , num=0;
while(1){
for(i=0;i<64;i++){
inputc=input=FileRead_getc(fp);//1文字取得する
if(inputc=='/'){//スラッシュがあれば
while(FileRead_getc(fp)!='\n');//改行までループ
i=-1;//カウンタを最初に戻して
continue;
}
if(input==',' || input=='\n'){//カンマか改行なら
inputc='\0';//そこまでを文字列とし
break;
}
if(input==EOF){//ファイルの終わりなら
goto EXFILE;//終了
}
}
switch(num){
case 0: enemy_order[n].cnt =atoi(inputc);break;
case 1: enemy_order[n].pattern =atoi(inputc);break;
case 2: enemy_order[n].knd =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].col =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++;
}
}
EXFILE:
FileRead_close(fp);
}


ご教授お願いします。

Re:リードエラーと出てきます。。

Posted: 2010年11月10日(水) 21:39
by みけCAT
変数のスコープの関係で、FileRead_open関数に渡しているfnameには何も入っていません。
(ゴミが入っているかもしれません)
代入ではなくlstrcpy() APIを使ってください。

Re:リードエラーと出てきます。。

Posted: 2010年11月10日(水) 21:39
by dic
人にソース見て欲しかったらインデントくらいはそろえたほうがいいと私なりの意見です

みたところ赤い字のところのswich文に break がみあたりませんが そのまま処理ながれてませんか?

Re:リードエラーと出てきます。。

Posted: 2010年11月10日(水) 21:49
by みけCAT
aをstatic変数にして、
switchの中にbreakを適切に入れないと、
期待した動作にならないのではないかと思います。

Re:リードエラーと出てきます。。

Posted: 2010年11月10日(水) 21:53
by みけCAT
ファイル名の
../dat/csv/storyH

.csv
の部分は共通なので、
出来ればwsprintf() APIでファイル名を作ったほうがいいのではないかと思います。

Re:リードエラーと出てきます。。

Posted: 2010年11月11日(木) 19:23
by MATTARI
お返事有難うございます。

>みけCAT
breakが抜けていたので入れてみました。
wsprintf() API というのがよくわからないです。。

>dic
インデントの揃え方いまいち分かりませんが頑張ってみます。

以下のように変更してみました。

//敵の出現情報をエクセルから読み込んで格納する関数
void load_story(){
int n,num,i,fp;
static int a=1;
char fname[32];
switch(a){
case 1:
lstrcpy(fname,"../dat/storyH1.csv");
if(boss.knd==boss.danmaku_num[1])
a=2;break;
case 2:
lstrcpy(fname,"../dat/storyH2.csv");
if(boss.knd==boss.danmaku_num[1])
a=3;break;
}



1面のcsvは読み込んでくれました。
2面のcsvはリードエラーとは出ませんが、敵が出てきません。

Re:リードエラーと出てきます。。

Posted: 2010年11月11日(木) 21:35
by dic
エラーをつかむようにswitch文に default を追加しました
どこかでエラーが起きているかもしれないですね
期待してない動作をしてないかエラーチェック機能をつけくわえるといいかもしれないです

2面のcsvを読み込まないのは おそらく int a=1 の値が変更されてない可能性があるかと私なりの推測です

また、char fname[32]; が色々宣言されているので、別の変数名を使われてみてはどうでしょうか?
fname1,fname2 とかですね
fname1 -> 1面のcsvファイル名
fname2 -> 2面のcsvファイル名

void load_story()
{
    int n,num,i,fp,a=1;
    char fname[32];
    switch(a)
    {
    case 1:
        char fname[32]={"../dat/csv/storyH1.csv"};
        //    アドバイス(dic) boss.knd == boss.danmaku_num[1] が一致しないと a = 2 にならない
        if(boss.knd==boss.danmaku_num[1])
            a=2;
        break;
    case 2:
        char fname[32]={"../dat/csv/storyH2.csv"};
        if(boss.knd==boss.danmaku_num[1])
            a=3;
        break;

        //    追加(dic)
    default:
        printDx( "error 実装されていない aの値です\n" );
        break;
    }

    int input[64];
    char inputc[64];

    fp = FileRead_open(fname);//ファイル読み込み fname の中身が初期化されていない(dic)
//  ブレークポイントを設定してここでのfanmeの変数の中身を確認することをお勧めします
    if(fp == NULL){
        printfDx("read error\n");
        return;
    }
    for(i=0;i<2;i++)//最初の2行読み飛ばす
        while(FileRead_getc(fp)!='\n');

    n=0 , num=0;
    while(1){
        for(i=0;i<64;i++)
        {
            inputc=input=FileRead_getc(fp);//1文字取得する
//=============================================================
//    宣言    int FileRead_getc( int FileHandle ) ;
//    概略     ファイルから一文字読み出す
//    引数     int FileHandle : ファイルハンドル
//    戻り値     -1以外:読み出した文字コード
//    -1:エラー発生
//    解説      FileRead_open関数で開いたファイルから一文字読み込みます。
// 正常に読み込めるのは1バイト文字だけで、一文字2バイトの全角文字などは正常に読み込めません。(1バイト目だけが返ってきます)
//            とリファレンスにあるので inputc = input は型が一致しないですね (コンパイルが通ったのが不思議ですが)
//=============================================================


            if(inputc=='/'){//スラッシュがあれば
                while(FileRead_getc(fp)!='\n');//改行までループ
//            i=-1;//カウンタを最初に戻して
                continue;
            }
            if(input==',' || input=='\n'){//カンマか改行なら
                inputc='\0';//そこまでを文字列とし
                break;
            }
// input の変数の中身は通常の変数の値が代入されます
// EOFを返すのは feof(fp); の feof関数です
// DxLibの使用では代入されるかもしれませんが、ここは私の調査不足です
// i<64とループの条件にあるので 64+2行以内しか読み込めません
            if(input==EOF){//ファイルの終わりなら
                goto EXFILE;//終了
            }
        }
        switch(num){
            case 0:    enemy_order[n].cnt        =atoi(inputc);break;
            case 1:    enemy_order[n].pattern    =atoi(inputc);break;
            case 2:    enemy_order[n].knd        =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].col        =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;

            //    追加(dic)
            default:
                printfDx( "error 実装されていないnumの値です\n" );    //    追加
                break;
        }
        num++;
        if(num==18){
            num=0;
            n++;
        }
    }
EXFILE:
    FileRead_close(fp);
}



//=============================================
編集:結構コメントを追加しました 画像

Re:リードエラーと出てきます。。

Posted: 2010年11月11日(木) 22:17
by Dixq (管理人)
> インデントの揃え方いまいち分かりませんが頑張ってみます。

フォーマットを整えたい範囲を範囲指定して

編集 > 詳細 > 選択範囲のフォーマット

をしてから投稿するだけで綺麗に表示できると思いますよ。
HTMLで表示する場合タブは空白4つで表現するとなお良いでしょう。

Re:リードエラーと出てきます。。

Posted: 2010年11月12日(金) 00:21
by MATTARI
お返事有難うございます。

>dicさん
丁寧な解説有難うございます!
defaultはエラー発見のためにも必要なんですね。
変数名もfname1やfname2を使うようにしてみます。

しかし、これでは case の中を{}でくくらないと以下のようなコンパイルエラーが出てきました。。
'fname' の初期化が 'case' ラベルによって行われませんでした。
'fname' : 再定義されています。2 回以上初期化されています。
'fname' の初期化が 'default' ラベルによって行われませんでした。

{}でくくってみたらコンパイルできたのですが、今度はリードエラーと出てきました。。

>Dixqさん
こんな裏技的なのがあるなんて驚きました。。有難うございます!



試行錯誤してがんばってみます。。

Re:リードエラーと出てきます。。

Posted: 2010年11月12日(金) 16:24
by dic
返事がおくれました
void load_story()
{
    //    みけCATさんがおっしゃるように static 変数にしないと2回目以降の呼び出し時に a=1 になってしまう
    //    これを避けるため static int にして 2回目以降の呼び出しのとき、前の値を保持している状態にする
    static    int    a = 1;
    int n,num,i,fp;
    char fname[32];//    みけCATさんがおっしゃるように これが初期化されていない
    switch(a)
    {
    case 1:
        {
            //    fname1 とする
            char fname1[32]={"../dat/csv/storyH1.csv"};
            //    アドバイス(dic) boss.knd == boss.danmaku_num[1] が一致しないと a = 2 にならない
            if(boss.knd==boss.danmaku_num[1])
                a=2;
            //    追加
            strcpy( fname, "../dat/csv/storyH1.csv" );    //    fname を初期化する
            break;
        }
        //    fname1 は有効な範囲を超えたので有効でない
    case 2:
        {
            char fname2[32]={"../dat/csv/storyH2.csv"};
            if(boss.knd==boss.danmaku_num[1])
                a=3;
            //    追加
            strcpy( fname, "../dat/csv/storyH2.csv" );    //    fname を初期化する
            break;
        }
        //    fname2 は有効な範囲を超えたので有効でない

        //    追加(dic)
    default:
        printDx( "error 実装されていない aの値です\n" );
        break;
    }

    int input[64];
    char inputc[64];

    //    うえにあるように fname の中身が代入されてない おそらく中身はフフフフフフフフフフフフ
    //    追加の strcpy でfnameを初期化してたらOK
    fp = FileRead_open(fname);//ファイル読み込み
    if(fp == NULL){
        printfDx("read error\n");
        return;
    }
    ...
        ...
            ...
EXFILE:
    FileRead_close(fp);
}
画像

Re:リードエラーと出てきます。。

Posted: 2010年11月12日(金) 16:26
by みけCAT
char fname[32];// みけCATさんがおっしゃるように これが初期化されていない
のところを
char fname[32]={0,};// みけCATさんがおっしゃるように これが初期化されていない
//とりあえず0で初期化
のようにした方が安全だと思います。
初期化しないと最悪大変なことになりますが、
これだとたぶんリードエラーだけですむでしょう。

Re:リードエラーと出てきます。。

Posted: 2010年11月12日(金) 19:08
by MATTARI
お返事有難うございます。

>dicさん
とても参考になります!
strcpyで初期化するんですね。了解です。

>みけCATさん
char fname[32]={0,};
の0で初期化ですが、0の後の コンマ はなぜ必要なのでしょうか?


//敵の出現情報をエクセルから読み込んで格納する関数
void load_story(){
static int a=1;
int n,num,i,fp;
char fname[32]={0,}, *strcpy(char *s1, const char *s2);
switch(a){
case 1:
{
// fname1 とする
char fname1[32]={"../dat/csv/storyH1.csv"};
// アドバイス(dic) boss.knd == boss.danmaku_num[1] が一致しないと a = 2 にならない
if(boss.knd==boss.danmaku_num[1])
a=2;
// 追加
strcpy( fname, "../dat/csv/storyH1.csv" ); // fname を初期化する
break;
}
// fname1 は有効な範囲を超えたので有効でない
case 2:
{
char fname2[32]={"../dat/csv/storyH2.csv"};
if(boss.knd==boss.danmaku_num[1])
a=3;
// 追加
strcpy( fname, "../dat/csv/storyH2.csv" ); // fname を初期化する
break;
}
// fname2 は有効な範囲を超えたので有効でない

// 追加(dic)
default:
printf( "error 実装されていない aの値です\n" );
break;
}


これでコンパイルはできたのですが、リードエラーとでてきました。。

Re:リードエラーと出てきます。。

Posted: 2010年11月12日(金) 21:28
by みけCAT
>0の後のコンマはなぜ必要なのでしょうか?
別のスレッドでこの方法で配列を初期化していたので使ってみました。
コンマは要らないかもしれません。

Re:リードエラーと出てきます。。

Posted: 2010年11月13日(土) 12:11
by dic
fp = FileRead_open(fname);//ファイル読み込み
    if(fp == NULL){
        printfDx("read error\n");
        return;
    }
    ...
        ...
            ...
リードエラーというと上のところでしょうか?
だとしたら fname が初期化されてない可能性が高いです
VC++ だったら F9 でブレークポイントを設定できるので、ブレークポイントを設定してみて
fname 変数の中身を確認してみてください

Re:リードエラーと出てきます。。

Posted: 2010年11月13日(土) 15:05
by ゆーずぃ
>0の後のコンマはなぜ必要なのでしょうか?

別に必要ないです。
ただ、enumの宣言の時とかも同じですけど、コンマを付けておくと後で要素を追加する際に楽になります。
一応コンマの付け忘れでコンパイルエラー、なんてのも防げます。それだけです。
switch-case文の最後のcaseにもその後のcase追加を考えてbreak;を付けておくのと同じ様な意味合いですね。

ただし、この書き方はC++なら出来るけどCでは出来ないとかもあった気がします。親切すぎるVC++だとコンマが多いって怒られるかもしれませんね。私は普段 a[10] = {0}; でやってるのでそこまでは分かりませんが。

Re:リードエラーと出てきます。。

Posted: 2010年11月13日(土) 15:12
by MATTARI
お返事有難うございます。

>みけCATさん
コンマは無くてもいい。。了解です。

>dicさん
リードエラーの原因はただ読み込むパスを間違えていました^^;;
とりあえず、もうリードエラーはないようなのですが。。

コンパイルするとこんな感じです。

1面のcsvは読み込みました。敵がちゃんと出てきます。

1面のボスを倒しました。

2面のcsvを読み込みました。(リードエラーと出てこないから、たぶん読み込んだ?)
ですが、敵が出てきません。

Re:リードエラーと出てきます。。

Posted: 2010年11月13日(土) 19:14
by dic
char    hoge[1024];
    fp = FileRead_open(fname);//ファイル読み込み
    if(fp == NULL){
        //    追加
        sprintf( hoge, "%s が読み込めませんでした", fname );
        MessageBox( NULL, hoge, "error", MB_OK );
        printfDx("read error\n");
        return;
    }
    //    追加
    sprintf( hoge, "%s を読み込みました", fname );
    MessageBox( NULL, hoge, "error", MB_OK );
    ...
        ...
            ...
EXFILE:
    FileRead_close(fp);
としてきちんと読み込んでいるか確認してみてください

Re:リードエラーと出てきます。。

Posted: 2010年11月13日(土) 20:41
by MATTARI
お返事有難うございます。

>ゆーずぃさん
コンマについての詳しい説明有難うございます。
今回はコンマ無しでやってみます。

>dicさん
以下のようにしてみました。

void load_story(){
static int a=1;
int n,num,i,fp;
char fname[32]={0}, *strcpy(char *s1, const char *s2), hoge[1024];
switch(a){
case 1:
{
// fname1 とする
char fname1[32]={"../dat/storyH1.csv"};
if(boss.knd==boss.danmaku_num[1])
a=2;
strcpy( fname, "../dat/storyH1.csv" ); // fname を初期化する
break;
}
// fname1 は有効な範囲を超えたので有効でない
case 2:
{
char fname2[32]={"../dat/storyH2.csv"};
if(boss.knd==boss.danmaku_num[1])
a=3;
strcpy( fname, "../dat/storyH2.csv" ); // fname を初期化する
break;
}
// fname2 は有効な範囲を超えたので有効でない
default:
printf( "error 実装されていない aの値です\n" );
break;
}
int input[64];
char inputc[64];

fp = FileRead_open(fname);//ファイル読み込み
if(fp == NULL){
printfDx("read error\n");
// 追加
sprintf( hoge, "%s が読み込めませんでした", fname );
MessageBox( NULL, hoge, "error", MB_OK );
printfDx("read error\n");
return;
}
// 追加
sprintf( hoge, "%s を読み込みました", fname );
MessageBox( NULL, hoge, "error", MB_OK );



一番最初に../dat/storyH1.csvを読み込みました。と出てきました。
2面に入ると何も表示されず、敵も出ずといった感じです。。

Re:リードエラーと出てきます。。

Posted: 2010年11月13日(土) 21:51
by みけCAT
この関数の最初にMessageBox関数を追加し、
ちゃんとこの関数が呼ばれているか確認してみてください。

Re:リードエラーと出てきます。。

Posted: 2010年11月14日(日) 10:48
by MATTARI
>みけCATさん
>この関数の最初にMessageBox関数を追加し、
>ちゃんとこの関数が呼ばれているか確認してみてください。
この関数とはload_story()のことですよね?
MessageBoxなら面を読み込んだときに表示されるようになっているので、
そこでload_story()が呼び出されているのかがわかるような気がするのですが。。


2面へ移ったときにMessageBoxが出てこないということはどういうことなんでしょうか?

../dat/storyH2.csvを読み込みました。

または、

../dat/storyH2.csvを読み込めませんでした。

というメッセージが表示されないということはのは。。