アプリ版:「スタンプのみでお礼する」機能のリリースについて

拡張子をtxtファイルと、binファイルの両方で試したのですが同じように文字化けします。
ファイルの読み込み方が悪いのでしょうか?

読み込むファイル char_data.txt
Alice 1 15 10 8
Slime 1 10 8 3
Skeleton 2 15 11 7
Ghost 3 20 14 10
Dragon 100 3000 3000 300

//----------------------------------------------------
//ソース全文
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <windows.h>

#define N 5

typedef struct gamechar{
char name[32];
int lv;
int hp;
int mp;
int atk;
}GC;

void file_read(GC gc[]);
void status(GC pc, GC mc[], GC mc_copy[], int *num, int *lot);
void mons_change(GC pc, GC mc[], int *num);
void mons_multi(GC mc[], GC mc_copy[], int *num, int *lot);

int main(void)
{
int num=0, lot=0; //モンスターの種類選択用、複数作成用
GC gc[N];
GC pc; //プレイヤーキャラ用
GC mc[N]; //モンスター用
GC mc_copy[N]; //モンスターを複数作成する時用
srand((unsigned)time(NULL));
file_read(gc);
//ファイルデータ読み込み終了
memcpy(mc, gc, sizeof(gc));
pc=mc[0]; //mc[0]はプレイヤーキャラ
mons_change(pc, mc, &num);
mons_multi(mc, mc_copy, &num, &lot);
status(pc, mc, mc_copy, &num, &lot);
return 0;
}
void mons_multi(GC mc_copy[], GC mc[], int *num, int *lot)
{
*lot=rand()%5;
for(int i=0; i<(*lot); ++i){
mc_copy[i]=mc[*num];
}
}

//モンスターランダム切り替え
void mons_change(GC pc, GC mc[], int *num)
{
*num=rand()%N; // モンスターの種類を変える
}

//データファイル読み込み
void file_read(GC gc[])
{
FILE *fp;
int i=0;
if(fopen_s(&fp, "char_data.txt", "r")!=0){
exit(EXIT_FAILURE);
}
while(fscanf_s(fp,"%s%d%d%d%d", gc[i].name, _countof(gc[i].name), &gc[i].lv, &gc[i].hp, &gc[i].mp, &gc[i].atk)!=EOF){
++i;
}
fclose(fp);
}

// ステータス表示
void status(GC pc, GC mc[], GC mc_copy[], int *num, int *lot)
{
system("cls");
// printf("num 0:player_char 1:Slime 2:Skeleton 3:Ghost 4:Dragon\n\n");
puts("--------------------------------------------");
printf(" Lv%-4d%-16sHP%-10dMP%-10d\n", pc.lv, pc.name, pc.hp, pc.mp);
puts("");
printf(" %-36s%-1d匹\n", mc[*num].name, *lot);
puts("--------------------------------------------");

for(int i=0; i<(*lot); ++i){
printf(" %-37s%-1d\n", mc_copy[*num].name, i);
}
}

「テキストファイルから読み込んだ文字が文字」の質問画像

質問者からの補足コメント

  • うーん・・・

    ありがとうございます。
    残念ながら、メモ帳からANSIを選んで保存しても同じでした。
    他のテキストエディタ”Notepad++、CresentEve、Visual Stadio Codeなど”でシフトJISを選択して保存しても同じでした。
    また、何かわかりましたらよろしくお願いします。

    No.1の回答に寄せられた補足コメントです。 補足日時:2016/07/28 15:43
  • ありがとうございます。
    早速見直して、実行してみました。

    void status(GC pc, GC mc[], GC mc_copy[], int *num, int *lot);
    void mons_change(GC pc, GC mc[], int *num);
    void mons_multi(GC mc_copy[], GC mc[], int *num, int *lot);

    status(pc, mc, mc_copy, &num, &lot);
    mons_change(pc, mc, &num);
    mons_multi(mc_copy, mc, &num, &lot);

    変更後、文字化けせずに読み込めるようになりましたが、完全ではありませんでした。
    何度か実行すると、やはり文字化けしてしまいます。
    また何かわかりましたら、よろしくお願いします。

    No.2の回答に寄せられた補足コメントです。 補足日時:2016/07/28 16:11
  • 初期化の説明を参考にいろいろやってみた結果、これで解決できました。
    memcpy(mc, gc, sizeof(gc));
    memcpy(mc_copy, gc, sizeof(gc));

    memcpyで両方ともやってみたら、文字化けしなくなりました。
    ありがとうございました。

    No.5の回答に寄せられた補足コメントです。 補足日時:2016/07/28 19:33

A 回答 (5件)

GC mc[N] = { //モンスター用


 { "m0", 0, 0, 0, 0 },
 { "m1", 0, 0, 0, 0 },
 { "m2", 0, 0, 0, 0 },
 { "m3", 0, 0, 0, 0 },
 { "m4", 0, 0, 0, 0 }
};
GC mc_copy[N] = { //モンスターを複数作成する時用
 { "mc0", 0, 0, 0, 0 },
 { "mc1", 0, 0, 0, 0 },
 { "mc2", 0, 0, 0, 0 },
 { "mc3", 0, 0, 0, 0 },
 { "mc4", 0, 0, 0, 0 }
};

こんな感じにしておくと…少なくとも「未初期化のローカル変数」参照で文字化け(ゴミ)が表示されることはなくなるかと思いますよ。

memset()で構造体配列を0x00埋めしてしまう。というのも有りかもしれませんが。
ただし、その場合は
>printf(" %-37s%-1d\n", mc_copy[*num].name, i);
などで表示される文字列はなにもなし…になりますけどね。
この回答への補足あり
    • good
    • 1

見直し失敗した……。



とりあえず
> printf(" %-37s%-1d\n", mc_copy[*num].name, i);
で*numが*lotより大きい状態だと、mons_multi()でコピーしていない領域(つまり未初期化)を参照している…ということになります。

ローカル変数を特定の値にしておいた方がいいんじゃないですかねぇ……。
    • good
    • 0
この回答へのお礼

お手数おかけしてしまって、すみませんでした。
>ローカル変数を特定の値に・・・
指摘していただいたところを改めてやり直して、調べてみます。

お礼日時:2016/07/28 16:40

>何度か実行すると、やはり文字化けしてしまいます。



デバッグは自分でやってほしいところですが……。

>for(int i=0; i<(*lot); ++i){
> printf(" %-37s%-1d\n", mc_copy[*num].name, i);
>}

ループでぐりぐり回る(変化する)のはiです。
名前(?)の表示は第宇引数で渡された値です。
第4引数で渡される値は第5引数で渡される値より小さいことが保証されていますか?
    • good
    • 0

>ファイルの読み込み方が悪いのでしょうか?



ファイルから読み込んだ内容を捨てているからでは?

>file_read(gc);
で、gc[]に読み込みます。
>memcpy(mc, gc, sizeof(gc));
で、gc[]の内容をmc[]にコピーします。
>mons_multi(mc, mc_copy, &num, &lot);
で、未初期化のmc_copy[]をmc[]にコピーします。
>status(pc, mc, mc_copy, &num, &lot);
で、未初期化のmc_copy[]を表示しようとします。
>printf(" %-37s%-1d\n", mc_copy[*num].name, i);
の部分ね。

関数に渡す変数と、関数側で受け取って使っている仮引数の名前に注意するべきでしょう。

>mons_multi(mc, mc_copy, &num, &lot);
では、第1引数はmc[]、第2引数はmc_copy[]で渡しています。
が、受け取る
>void mons_multi(GC mc_copy[], GC mc[], int *num, int *lot)
では、第1引数がmc_copy[]で第2引数がmc[]です。
処理内容により、mc[]からmc_copy[]にコピーされます。
つまり、mons_multi()の中では下記の対応になります。
 mc_copy[] => main()のmc[]
 mc[] => main()のmc_copy[]
この回答への補足あり
    • good
    • 0
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています