質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

264閲覧

cで2次元配列(2重ポインタでも固定長配列どちらでもいいので)のfreadとfwriteでファイル読み書き方法教えてください

littlestream

総合スコア36

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2024/04/04 00:14

編集2024/04/04 09:42

イメージ説明### 実現したいこと
最近自作ゲーム用のマップエディタをc言語とDXLIBで作っているのですが、
肝心のファイルのセーブとロードの(つまり、読み書き)をバイナリファイルでしたいです。

発生している問題・分からないこと

fwriteやfreadで2次元配列を固定長で読み書きしているつもりなのにマップエディタの
マップに反映されないのは何故なのか分からないです。
しかし、マップデータをバイナリエディタを見てみると、03C0までデータは00で
埋められています。

該当のソースコード

c

1char MapData[32][30]={0}; 2...飛ばします 3if(Saveボタンをクリックしたら){ 4 FILE *fp; 5 fp=fopen("DQmodoki.bin","wb"); 6 if(fp==NULL) return -1; 7 fwrite(MapData,sizeof(MapData),1,fp); 8 fclose(fp); 9} 10if(Loadボタンをクリックしたら){ 11 FILE *fp; 12 fp=fopen("DQmodoki.bin","rb"); 13 if(fp==NULL) return -1; 14 fread(MapData,sizeof(MapData),1,fp); 15 fclose(fp); 16}
特になし

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

2次元配列を一次元配列にしたら、何故か、縦一列が書きこまれたり、
ポインタのポインタにしたら、突然終了したりしました。
もしくは、ネットで調べたら下記の書き込みが良いそうでしたがうまく行きませんでした。
char MapData[1024][32];
FILE *fp;fp=fopen("DQmodoki.bin","wb");if(fp==NULL)return -1;
for(int i=0;i<1024;i++)
{
fwrite(MapData[i],sizeof(char),32,fp);
}

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

littlestream

2024/04/04 00:17

縦一列に書き込まれたという記述は、マップエディタのマップ画面の話です。
littlestream

2024/04/04 00:19

また、マップエディタは、マップ画面にはきちんとマップチップのパレットから うまく書き込まれているので、ファイル処理がおかしいとしか思えないのです。
int32_t

2024/04/04 00:34

> しかし、マップデータをバイナリエディタを見てみると、03C0までデータは00で 埋められています。 それは期待通りなのですか、そうではないのですか。 期待通りではない場合、どうなっているべきなのでしょうか。
otn

2024/04/04 01:20 編集

お書きの部分には間違いは無いです。「読み書き方法教えてください」ということだと「その方法で合ってます」が答えです。 > マップエディタのマップに反映されない 具体的な現象は何でしょうか?否定形を使わないで表現しましょう。 「~~~とならない」だと一体何が起こっているのか全く伝わりません。 この文の「マップエディタ」は今あなたが作っているプログラムのことですか? であれば、コードも含めて示しましょう。 「下記のコードを実行した際に、~~~という表示を期待したが、実際に表示されたのは~~~であった」のように書くと、他人にも何が起こっているのか伝わります。
jimbe

2024/04/04 03:37 編集

>2次元配列を一次元配列にしたら、何故か、縦一列が書きこまれたり、 >ポインタのポインタにしたら~ 試行錯誤のやりかたが間違っているように感じます。 ご自身がやりたいことを c 言語でどう書くのかを分からないまま一次元だのポインタのポインタだのと弄るのは、ラーメンを作ろうとしてそばを入れてみたとか炒めてみたとかとかいうことをやっているのと同じです。プログラミングは運試しではありません。 1 バイトの入出力さえ出来れば後はループを用いれば何次元配列でも出来ることはお分かりになっていると思います。ますはそれで書いてみては如何でしょうか。 なんならバイナリで無く CSV のようなテキストファイルでまず書いてみてから最終的にバイナリ化したほうが、確認やテスト等し易いかもしれません。
fana

2024/04/04 04:59

配列サイズを変えても話は変わらないのでしょうから,こういう場所で訊く場合には 具体的な値を明示した小さい配列を例にして「この実装だとこういうバイナリが出力されていて変だ」とかなんとか具体的に論じればよいのでは. > 03C0までデータは00で埋められています とか言われても,正直何言ってるのか微塵もわからないので. 例えば char MapData[3][2] = { {1,2}, {10,20}, {100,200} }; みたいなのをファイルに出力したらそのファイルの内容は実際どうなるのか,それがあなたの想定するファイル内容とはどのように異なっているのか,といった話を示せば良いのでは. (このサイズで問題が解決するなら,あなたの実際のサイズでも同様に解決するでしょ)
guest

回答4

0

char MapData[3][3]={
0,1,2,
3,4,5,
6,7,8
};
FILE *fp=fopen("test.bin","wb");
if(fp==NULL)return -1;
fwrite(MapData,sizeof(MapData),1,fp);
fclose(fp);
で大丈夫でした。書き込みしてくれたみなさん、ありがとうございました。

投稿2024/04/06 09:11

littlestream

総合スコア36

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

イメージ説明
こんなマップエディタです。ちなみに、ファミコンのCHR-ROMデータを直接読み込んでいます。
そして、マウスでマップチップのパレットから選択してパレットも0~3番から読み込むことで
マップ画面をドラッグするとパレットごと反映します。

投稿2024/04/04 07:17

littlestream

総合スコア36

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2024/04/04 08:31

質問は編集出来ますので、このような情報は質問に追加編集されたほうが良いと思います。
littlestream

2024/04/04 09:41

分かりました。jimbeさん、アドバイスありがとうございます。
jimbe

2024/04/04 11:18

編集ありがとうございます。
guest

0

自己解決

ファイル読み込みは、
if(ロードボタンをクリックしたら)
{
FILE *fp;
int i,n;
fp=fopen(szFile,"rb");
for( i = 0;i < MaxY; i++){
for(int j=0;j<MaxX;j++)
{
fread(&MapData[i][j],sizeof(char),1,fp);
}
}
fclose(fp);
}

で上手く行きました。上手くいったというのは、
マウスカーソルでクリックした座標のデータが上手く
読み込みと書き込みに成功したということです。

本当にありがとうございました。

投稿2024/04/04 07:09

littlestream

総合スコア36

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2024/04/04 08:27

このコードは、 szFile が "DQmodoki.bin"で、MaxY が 32で、MaxX が 30なら、 質問文の11~15行目と等価なので、やはり、質問文に書かれていない所に間違いがあったのでしょう。
littlestream

2024/04/04 11:47

otnさん、コメントありがとうございます。 う~ん、個人的には、(そういえば2次元配列の読み書きってどうやったっけ??) って感じだったので、ネットを参照すると、やはり同じような悩みを持つ人も多くいたように 感じました。ですが、それらの方々は、きっと動的に(2次元?)配列を持ちたかったから 悩んでいるようにも見えました。 なので、自分も訳も分からずにnewとかdeleteとか、一次元配列を使ってしまい、 余計に混乱したような感じはしました。 自分にさらに間違えがあるとすると、マップ画面が1マスが16x16が一行16で全ての列が15なので、 もともと32x30なので計算間違えをしたのが、 そのまま偶然コンパイルを通ってしまっていたのは間違えだったかと思います。
otn

2024/04/05 15:27

プログラミングに慣れない人は、少し長いプログラムを書く時に、 「多分こうだろう」とか「ググったらこう書いてあった」みたいな感じで、全体のプログラムを全て書き上げてから、一気に動かして、「うまくいく」「うまくいかない」のゼロ・イチの判断をします。 失敗の場合は、全体のどこに間違いがあるのか見当もつかない。 慣れた人は、「自信がない部分」「初めて使う機能や関数」とかは、まず自分の理解が正しいことを確認するための短いテストプログラムを書いて、自分の理解が正しいことを確認してから、全体のプログラムに組み込みます。 そうすると、全部自分の手の内にある技術だけでプログラムが書けるので、細かいところでの問題は(タイプミスなど単純ミスをしない限り)発生しません。 短いテストプログラムを期待通り動かすことが出来ない場合は、その10行前後のプログラムについて質問すれば、問題の背景説明もしなくて済むし、回答者も回答するのが簡単です。 今回だと、 char data[3][2] = {{'a','b'},{'c','d'},{'e','f'}}; というデータをファイルに書いて、abcdefg という中味の6バイトのファイルが出来るためのやり方を色々試せばいいわけです。
guest

0

「質問へのコメント」欄でも述べましたが,
まずはこのくらいのコードでも書いて,気が済むまで原理確認してください.

C

1#define MAP_H (3) 2#define MAP_W (2) 3 4int main() 5{ 6 char MapData[ MAP_H ][ MAP_W ] = { {0x1,0x2}, {0xA,0xB}, {0x3C,0x4D} }; 7 8 printf( "書出前:\n" ); 9 for( int y=0; y<MAP_H; ++y ) 10 { 11 for( int x=0; x<MAP_W; ++x ){ printf( "%d ", (int)MapData[y][x] ); } 12 printf( "\n" ); 13 } 14 printf( "\n" ); 15 16 {//書出 17 FILE *fp = fopen( "Test.bin", "wb" ); 18 if( fp == NULL )return 0; 19 fwrite( MapData, sizeof(char), MAP_H*MAP_W, fp ); 20 fclose( fp ); 21 printf( "書出完了\n" ); 22 } 23 24 //※後段の読込処理の成否が分かるように,一旦,MapData[][] の中身をてきとーな値にしている 25 for( int y=0; y<MAP_H; ++y ) 26 { 27 for( int x=0; x<MAP_W; ++x ) 28 { MapData[y][x] = 0x77; } 29 } 30 printf( "読込前:\n" ); 31 for( int y=0; y<MAP_H; ++y ) 32 { 33 for( int x=0; x<MAP_W; ++x ){ printf( "%d ", (int)MapData[y][x] ); } 34 printf( "\n" ); 35 } 36 printf( "\n" ); 37 38 {//読込 39 FILE *fp = fopen( "Test.bin", "rb" ); 40 if( fp == NULL )return 0; 41 fread( MapData, sizeof(char), MAP_H*MAP_W, fp ); 42 fclose( fp ); 43 printf( "読込完了\n" ); 44 } 45 printf( "読込後:\n" ); 46 for( int y=0; y<MAP_H; ++y ) 47 { 48 for( int x=0; x<MAP_W; ++x ){ printf( "%d ", (int)MapData[y][x] ); } 49 printf( "\n" ); 50 } 51 52 return 0; 53}

↑のコードの出力結果:
「読込後」が「書出前」と一致していることが確認できる.

書出前: 1 2 10 11 60 77 書出完了 読込前: 119 119 119 119 119 119 読込完了 読込後: 1 2 10 11 60 77

出力されたファイルをバイナリディタで見た様子:
MapData[3][2] の内容 6byte が想定通りに出力できていることがわかる.
イメージ説明

投稿2024/04/04 05:21

fana

総合スコア11663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2024/04/04 05:25

* この例で既に疑問があるのであれば,何がどう疑問なのかを述べる * あるいは仮に「配列サイズが 3*2 ならばできるけど 32*30 だとできないんだよ!」みたいな話とかであれば,そういうことを明確に述べる ……といったような応答でもあれば,質問内容がはっきりしてよかろう,とか思う.
littlestream

2024/04/04 06:54

恐らくですが、以前自分のブログで256x256のサイズで256色のBMPファイルを読み込んで ポリゴンのテクスチャーを描画したことがあるので、どうやら基本中の基本であることを 忘れかけていたようです。 恐らく、 char MapData[30][32]; FILE *fp; fp=fopen(filename,"wb"); for(int y=0;y<30;y++) { for(int x=0;x<32;x++) { fwrite(&MapData[y][x],sizeof(char),1,fp); } } fclose(fp); で書き込みが上手く行く可能性を感じました。
littlestream

2024/04/04 07:09

回答ありがとうございます。 試したところ問題が解決しました! ベストアンサーに選ばせていただきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問