データ入出力について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Libra

データ入出力について

#1

投稿記事 by Libra » 16年前

はじめまして。Libraと申します。
大学のサークルでC言語を後輩に教えているのですが、ファイル入出力の分野でcsvファイルの読み込みのソースを11章「エクセルを使って敵の出現データを作ってみよう」を参考に、C言語でファイル入出力を行いました。その際に疑問点が出たので質問します。

1)11章のload_story()関数内、int input[64]はどの様に使われているのか?は必要あるのか
2)11章のload_story()関数内、continue文上の『i=-1;//カウンタを最初に戻して』の部分は使われているのか?

1)に関して:int input[64]をchar inputc[64]に変更しても機能したのですが、何かしらinput[/url]を使わないと機能として不具合が生じる条件等があれば教えていただきたいです。
2)に関して:continue文の上のi=-1を抜いても普通に動きました・・・。continue文の仕様だとi=-1が無いとダメなハズなのですよね?上と同様に不具合が生じる条件等があれば教えていただきたいです。

ソースは以下の通りです。

#include<stdio.h>
#include<stdlib.h>

//構造体宣言(2次元配列を渡すため、変数charadataを構造体に)-----------
typedef struct charadata{
	int charadata[32][32];
}Charadata_t;

//プロトタイプ宣言===================================================
void LoadData(Charadata_t*chara);//データのロード
void DisplayData(Charadata_t*chara);//ロードしたデータの表示


//main関数===========================================================
int main(void){
	int i,j;
	Charadata_t chara;
	
	LoadData(&chara);
	DisplayData(&chara);
	
	return 0;
}




//ロードデータ関数----------------------------------------------------
void LoadData(Charadata_t *chara){
	FILE *fp;
    int i=0,j=0,num;
    char inputc[64];
	
	fp=fopen("data/data.csv","r");//ファイルを開く
   	if(fp==NULL){
		printf("ファイルのオープンに失敗しました。");
		exit(1);
	}
    while(1){
	    for(num=0;num<64;num++){
            inputc[num]=fgetc(fp);//1文字取得する
            if(inputc[num]=='/'){//スラッシュがあれば
                while(fgetc(fp)!='\n');//改行までループ
                continue;
            }
            if(inputc[num]==',' || inputc[num]=='\n'){//カンマか改行なら
                inputc[num]='\0';//そこまでを文字列とし
                break;
            }
            if(inputc[num]==EOF){//ファイルの終わりなら
				goto EXFILE;//終了
            }
     	}
		chara->charadata[j]=atoi(inputc);//読みとった文字を数字に変換
		j++;
		if(j==32){
			j=0;
			i++;
		}
	}
	EXFILE:
	fclose(fp);
}

//データ表示関数-----------------------------------------------
void DisplayData(Charadata_t*chara){
	int i,j;
	for(i=0;i<32;i++){
		for(j=0;j<32;j++){
			if(chara->charadata[j]==0){
				printf("□");
			}
			else if(chara->charadata[j]==1){
				printf("■");
			}
			//読み込むデータに二桁の数字を入れた場合も使用してみるため
			else if(chara->charadata[j]==10){
				printf("●");
			}
		}
		printf("\n");
	}
}


また、読み込むファイルを添付したファイルも添付します。
コマンドライン上で32×32の絵が表示されます。

Justy

Re:データ入出力について

#2

投稿記事 by Justy » 16年前


>1)に関して

 まず第一に FileRead_getc() / fgetc()の戻り値は int型です。
 その戻り値を charで受けると、EOFの判定が正しくできないことがあります。
 その為、文字列として格納するために inputcに、EOFや文字の判定の為の変数として inputに格納しているのでしょう。

 とはいえ、inputに関しては配列である必要はなく、ふつうの int型の変数でいいとは思います。



>2)に関して

 一見それで動いているように見えますが、結果としてはおかしな挙動になります。
 
 i=-1が無い場合、iの値はそのままで continueされ、forの中で ++iされます。
 ここで csvの次の行の先頭の文字を調べる処理に入ることになりますが、
ここで iの値が 0になっていないと inputcは前の行の文字も引き継いだ状態に
なってしまいます。

 今回のコードですと、

・ 最初の文字を取得する -> inputc[0]に '/'が代入される
・ 1行空読みして continue
・ forの先頭で num++されて、numは 1になる
・ 次の文字を取得する -> inputc[1]に 次の文字が格納される。

 さて、ここまで来たときに inputc[0]には前の行の '/'が残ったままになっています。

・ そのまま続いて文字を読み、どこかでカンマか改行が来たので breakして
文字を数字に変換する。
 -> inputcの先頭が '/'なので、変換失敗!

 これはマズイですよね?

 試しに csvの2行目のデータ('/'のある次の行)の先頭のデータを 0以外の
数値にしてみて下さい。

Dixq (管理人)

Re:データ入出力について

#3

投稿記事 by Dixq (管理人) » 16年前

仰る通り、inputが配列である必要ないですね(汗

それにしても我ながら何と言う意味のわかりにくい変数名・・。
どっちかというとinputcの方が一文字だけ入りそうな感じしますね・・。

とりあえず

int input;

にしておいて

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

でいいですね。
あ~なんかあちこち修正したいところだらけ何ですが、
こういうのって一回公開すると変更できないのが辛いですね・・。
全ての章の内容変えないといけなくなるし・・。
今まで読みなれた人にも迷惑かけてしまうし、
支館にも影響与えるでしょうし・・orz
 

Libra

Re:データ入出力について

#4

投稿記事 by Libra » 16年前

お二方共、的確で素早い解答ありがとうございます。

<Justy様
2)に関してですが、データが0の時『□』を、データが1の時『■』を表示するようにしていたので、たまたま上手くいってしまっていたようです。指摘の通り、『/』の次の行に0以外のデータを入れると見事に失敗しました。

<Dixq (管理人)様
館ページを参考に、シューティングゲームを作成しているのですが、csvファイルを知る前は全て敵のデータをプログラム内に書いていました。そのため、データ入力だけで3000行以上書いていました(汗)。とても参考になってます。

現在、シューティングゲームを作成しており、数ヶ月後にはステージ1くらいは完成出来そうなので、その時またご指導等よろしくお願いします。

閉鎖

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