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

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

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

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

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

Q&A

1回答

1990閲覧

fopen_sを使った座標のセーブ、ロード

matsu0o

総合スコア0

C

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

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

0グッド

0クリップ

投稿2021/06/27 00:33

編集2022/01/12 10:55

前提・実現したいこと

dxライブラリを使いマウスで線を引くようなプログラムを作っています。今回はその書いた線をfwrite,freadを使って保存、読み込みをしたいと考えています

発生している問題・エラーメッセージ

保存の方はできているらしいのですが読み込みの時がうまくいきません(例外スロー)。自分が思うにlineCnt,buf_cntあたりがおかしいのかなとは思うのですがどこをどう直せばいいのか分からない状況です

該当のソースコード

c

1#include "DxLib.h" 2#include <stdlib.h> 3#include<stdio.h> 4const int WIN_WIDTH = 920; //ウィンドウ横幅 5const int WIN_HEIGHT = 600;//ウィンドウ縦幅 6 7//モードの構造体 8enum PTYPE 9{ 10 Non, 11 Pen, 12 pen2, 13 Eraser, 14}; 15 16//線の構造体(座標、色) 17typedef struct line 18{ 19 float BlackLineX; 20 float BlackLineY; 21 int color; 22 23 PTYPE Ptype; 24}line; 25 26 27int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 28{ 29 //初期化前の設定 30 ChangeWindowMode(TRUE); 31 SetGraphMode(WIN_WIDTH, WIN_HEIGHT, 32); 32 33 //DXライブラリ初期化 34 if (DxLib_Init() == -1)return -1; 35 36 //背景色設定 37 SetDrawScreen(DX_SCREEN_BACK); 38 SetBackgroundColor(50, 50, 50); 39 float speed = 3; 40 int lineMaX = 1000; 41 //カウント用の変数 42 float len = 0; 43 int lineCnt = 0; 44 //セーブ、ロード用の変数 45 float buf_x[1000]; 46 float buf_y[1000]; 47 float buf_x2[1000]; 48 float buf_y2[1000]; 49 int buf_cnt = 0; 50 int buf_cnt2 = 0; 51 52 FILE* fp; 53 FILE* fp2; 54 FILE* fp3; 55 56 //malloc 57 line* bline; 58 bline = (line*)malloc(lineMaX * sizeof(line)); 59 60 if (bline == NULL) { 61 return 0; 62 } 63 64 //マウス情報用変数 65 int posX, posY; 66 bool Drag = false, penflag = true; 67 int type = 0; 68 //キー入力用変数 69 char KeyBuf[256]; 70 71 int save=0; 72 int load = 0; 73 //メインループ 74 while (!ProcessMessage()) 75 { 76 ClearDrawScreen(); 77 //キー入力1 78 GetHitKeyStateAll(KeyBuf); 79 80 if (KeyBuf[KEY_INPUT_1] == 1) { penflag = true; } 81 if (KeyBuf[KEY_INPUT_2] == 1) { penflag = false; Drag = false; } 82 if (KeyBuf[KEY_INPUT_0] == 1) { lineCnt = 0; } 83 84 85 86 //色の切り替え 87 if (KeyBuf[KEY_INPUT_A] == 1) { type = 0; } 88 if (KeyBuf[KEY_INPUT_R] == 1) { type = 1; } 89 if (KeyBuf[KEY_INPUT_G] == 1) { type = 2; } 90 if (KeyBuf[KEY_INPUT_B] == 1) { type = 3; } 91 if (KeyBuf[KEY_INPUT_5] == 1) { bline[lineCnt].Ptype = pen2; } 92 //マウス座標取得 93 GetMousePoint(&posX, &posY); 94 95 //マウス入力処理 96 if (GetMouseInput() & MOUSE_INPUT_LEFT) {//mouseが押されたとき 97 98 //ドラッグ中は座標を追加 99 bline[lineCnt].BlackLineX = posX; 100 bline[lineCnt].BlackLineY = posY; 101 102 //ドラッグ中は線を引く 103 if (penflag) { 104 if (Drag) { 105 bline[lineCnt].Ptype = Pen;//modeをペンに 106 } 107 108 //ドラッグ開始 drag中ではない 109 else { 110 Drag = true; //ドラッグフラグをオンにする 111 bline[lineCnt].Ptype = Non; 112 } 113 } 114 //penflagがfalseの時typeを消しゴムに 115 else { 116 bline[lineCnt].Ptype = Eraser; 117 } 118 119 //mouse座標に毎フレーム座標を追加している 120 lineCnt++; 121 //メモリが足りなくなったら拡大 122 //relloc 123 if (lineCnt == lineMaX) {//最大数なったら 124 lineMaX += 1000;//1000増やす 125 line* tmp = (line*)realloc(bline, lineMaX * sizeof(line)); 126 if (tmp == NULL) { 127 free(bline); 128 return -1; 129 } 130 bline = tmp; 131 } 132 } 133 134 else {//マウスのキーは押されていない 135 if (Drag)Drag = false; //ドラッグフラグをオフにする 136 } 137 138 //色の切り替え 139 if (type == 0) { bline[lineCnt].color = GetColor(255, 255, 255); } else if (type == 1) { bline[lineCnt].color = GetColor(255, 0, 0); } else if (type == 2) { bline[lineCnt].color = GetColor(0, 255, 0); } else if (type == 3) { bline[lineCnt].color = GetColor(0, 0, 255); } 140 141 //bline配列の情報を描画 142 for (int i = 0; i < lineCnt; i++) { 143 switch (bline[i].Ptype) 144 { 145 //pen書くとき 146 case Pen: 147 //一つ前の座標から今の座標へつなぐ線 148 DrawLine(bline[i - 1].BlackLineX, bline[i - 1].BlackLineY, bline[i].BlackLineX, bline[i].BlackLineY, bline[i].color,6); 149 150 break; 151 //消しゴム描くとき 152 case Eraser: 153 DrawBox(bline[i].BlackLineX - 20, bline[i].BlackLineY - 20, bline[i].BlackLineX + 20, bline[i].BlackLineY + 20, GetColor(5,5,5), TRUE); 154 break; 155 } 156 } 157 158 //セーブ 159 if (KeyBuf[KEY_INPUT_S] == 1) { 160 save = 1; 161 } 162 //ロード 163 if (KeyBuf[KEY_INPUT_L] == 1) { 164 load = 1; 165 } 166 167 //線のセーブ部分(現在使われてる配列の要素数、線分のx座標、線分のy座標) 168 if (save == 1) { 169 buf_cnt = lineCnt; 170 for (int i = 0; i < lineCnt; i++) { 171 buf_x[i] = bline[i].BlackLineX; 172 buf_y[i] = bline[i].BlackLineY; 173 } 174 175 //使われた配列の要素数の保存 176 fopen_s(&fp3, "test.dat", "wb"); 177 if (fp3 == NULL) { 178 DrawFormatString(150, 300, GetColor(255, 255, 255), "セーブできません\n"); 179 } 180 else { 181 DrawFormatString(150, 300, GetColor(255, 255, 255), "buf_Cntセーブ成功:%d\n",buf_cnt); 182 fwrite(&buf_cnt, sizeof(int), 1, fp3); 183 fclose(fp3); 184 } 185 186 //x座標の保存 187 fopen_s(&fp, "test.dat", "wb"); 188 if (fp == NULL) { 189 DrawFormatString(150, 340, GetColor(255, 255, 255), "セーブできません\n"); 190 } 191 else { 192 DrawFormatString(150, 340, GetColor(255, 255, 255), "x座標セーブ成功\n"); 193 //buf_cnt分書き出し 194 fwrite(&buf_x, sizeof(float),buf_cnt, fp); 195 fclose(fp); 196 } 197 198 //y座標の保存 199 fopen_s(&fp2, "test.dat", "wb"); 200 if (fp2 == NULL) { 201 DrawFormatString(150, 380, GetColor(255, 255, 255), "セーブできません\n"); 202 } 203 else { 204 DrawFormatString(150, 380, GetColor(255, 255, 255), "Y座標セーブ成功\n"); 205 //buf_cnt分書き込み 206 fwrite(&buf_y, sizeof(float),buf_cnt, fp2); 207 fclose(fp2); 208 } 209 } 210 //線のロード 211 if (load == 1) { 212 //使われた配列の要素数の読み込み 213 fopen_s(&fp3, "test.dat", "rb"); 214 if(fp3==NULL){ 215 DrawFormatString(0, 300, GetColor(255, 255, 255), "ロードできません\n"); 216 } 217 else { 218 DrawFormatString(0, 300, GetColor(255, 255, 255), "ロード成功\n"); 219 fread(&buf_cnt2, sizeof(int), 1, fp3); 220 fclose(fp3); 221 lineCnt = buf_cnt2; 222 } 223 224 //x座標の保存 225 fopen_s(&fp, "test.dat", "rb"); 226 if (fp == NULL) { 227 DrawFormatString(0, 340, GetColor(255, 255, 255), "ロードできません\n"); 228 } 229 else { 230 DrawFormatString(0, 340, GetColor(255, 255, 255), "ロード成功\n"); 231 //buf_cnt分読み出し 232 fread(&buf_x2, sizeof(float),buf_cnt, fp); 233 fclose(fp); 234 for (int i = 0; i < buf_cnt; i++) { 235 bline[i].BlackLineX = buf_x2[i]; 236 } 237 } 238 239 //y座標の保存 240 fopen_s(&fp2, "test.dat", "rb"); 241 if (fp2 == NULL) { 242 DrawFormatString(0, 380, GetColor(255, 255, 255), "ロードできません\n"); 243 } 244 else { 245 DrawFormatString(0, 380, GetColor(255, 255, 255), "ロード成功\n"); 246 //buf_cnt分読み出し 247 fread(&buf_y2, sizeof(float), buf_cnt, fp2); 248 fclose(fp2); 249 for (int i = 0; i < buf_cnt; i++) { 250 bline[i].BlackLineY = buf_y2[i]; 251 } 252 } 253 } 254 255 //文字等描画 256 { 257 DrawString(0, 0, "キー操作:0=全削除 1=ペン 2=消しゴム", 0x0); 258 DrawFormatString(0, 32, GetColor(0, 0, 0), "現在の配列使用数:%d(確保数:%d)", lineCnt, lineMaX); 259 DrawFormatString(0, 64, GetColor(0, 255, 0), "線のセーブ:S"); 260 DrawFormatString(0, 96, GetColor(0, 255, 0), "線のロード:L"); 261 if (penflag) { 262 DrawString(0, 16, "現在のモード:ペン", 0x0); 263 DrawLine(posX, posY - 10, posX, posY + 10, 0x0); 264 DrawLine(posX - 10, posY, posX + 10, posY, 0x0); 265 } else { 266 DrawString(0, 16, "現在のモード:白塗り", 0x0) 267 ; 268 DrawBox(posX - 20, posY - 20, posX + 20, posY + 20, GetColor(255, 255, 255), TRUE); 269 DrawBox(posX - 20, posY - 20, posX + 20, posY + 20, GetColor(255, 255, 255), FALSE); 270 } 271 } 272 273 //表画面に転送 274 ScreenFlip(); 275 } 276 277 free(bline); 278 DxLib_End(); 279 280 return 0; 281}

試したこと

for文の中身とかを変えてみましたがそれでもうまく動いてくれませんでした

補足情報(FW/ツールのバージョンなど)

現在詰まっている所としてはセーブしてからロードする際、セーブ時に書いた線を画面に表示させたいのですが今のところだと何も表示されない状態です

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

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

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

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

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

itagagaki

2021/06/27 00:49

開発は何で行っていますか?
matsu0o

2021/06/27 11:36

Dxライブラリの方を使わせてもらっています
itagagaki

2021/06/27 11:38

お聞きしたのは、OSは何か、コンパイラは何かです
matsu0o

2021/06/27 11:43

申し訳ありません。OSの方はwindows コンパイラの方はMicrosoft visual C++ですね
itagagaki

2021/06/27 11:55

Visual Studioでしたらデバッグ実行して例外が起こったときに呼び出し履歴を見てみるなどしてみると良いと思いますが、それはやってみましたか?
matsu0o

2021/06/27 12:12

呼び出し履歴や出力ウィンドウは見ました これに関しては自分の知識不足なんですが書き込みアクセス違反くらいしか分らず他は正直何を書いているのかが全く分かりませんでした
guest

回答1

0

まず、fopen_sのヘルプを検索して見つけます。

fopen_s, _wfopen_s

このページを開いて、第三引数に"w"を渡したときに何が起きるのかを調べます。

"w" 書き込み用に空のファイルを開きます。 指定したファイルが既に存在すると、そのファイルの内容は破棄されます。

これを踏まえて質問のプログラムを見てみましょう。

C

1 //使われた配列の要素数の保存 2 fopen_s(&fp3, "test.dat", "wb"); 3 if (fp3 == NULL) { 4 DrawFormatString(150, 300, GetColor(255, 255, 255), "セーブできません\n"); 5 } 6 else { 7 DrawFormatString(150, 300, GetColor(255, 255, 255), "buf_Cntセーブ成功:%d\n",buf_cnt); 8 fwrite(&buf_cnt, sizeof(int), 1, fp3); 9 fclose(fp3); 10 } 11 12 //x座標の保存 13 fopen_s(&fp, "test.dat", "wb"); 14 if (fp == NULL) { 15 DrawFormatString(150, 340, GetColor(255, 255, 255), "セーブできません\n"); 16 } 17 else { 18 DrawFormatString(150, 340, GetColor(255, 255, 255), "x座標セーブ成功\n"); 19 //buf_cnt分書き出し 20 fwrite(&buf_x, sizeof(float),buf_cnt, fp); 21 fclose(fp); 22 } 23 24 //y座標の保存 25 fopen_s(&fp2, "test.dat", "wb"); 26 if (fp2 == NULL) { 27 DrawFormatString(150, 380, GetColor(255, 255, 255), "セーブできません\n"); 28 } 29 else { 30 DrawFormatString(150, 380, GetColor(255, 255, 255), "Y座標セーブ成功\n"); 31 //buf_cnt分書き込み 32 fwrite(&buf_y, sizeof(float),buf_cnt, fp2); 33 fclose(fp2); 34 }

最初にfopen_s(&fp3, "test.dat", "wb");でファイルを開いてbuf_cntを書き込みます。
次にfopen_s(&fp, "test.dat", "wb");で同じファイルを開きますが、指定したファイルが既に存在するので、そのファイルの内容は破棄されます。 つまり、直前に書き込んだbuf_cntの内容を破棄したうえでbuf_xを書き込みます。
最後にfopen_s(&fp2, "test.dat", "wb");で同じファイルを開きますが、指定したファイルが既に存在するので、そのファイルの内容は破棄されます。 つまり、直前に書き込んだbuf_xの内容を破棄したうえでbuf_yを書き込みます。

これで、何が起こっているか理解していただけたでしょうか。

1つのファイルに複数の情報を書き込みたいのであれば、1回だけfopen_sしたうえで、fwriteを必要な回数だけ繰り返すようにしてください。freadの側も同様です。

投稿2021/06/27 01:09

編集2021/06/27 01:31
actorbug

総合スコア2212

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

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

matsu0o

2021/06/27 11:53

なるほど 何回もfopenしてしまうと前に読み込んだ情報が消えてしまうということですか、、知りませんでした ありがとうございます コードとしてはこのような書き方で問題ないのでしょうか(書いた線の保存はまだですが 一応エラーの方は消えました) if (save == 1) { buf_cnt = lineCnt; for (int i = 0; i < buf_cnt; i++) { buf_x[i] = bline[i].BlackLineX; buf_y[i] = bline[i].BlackLineY; } //使われた配列の要素数の保存 fopen_s(&fp, "test.dat", "wb"); if (fp == NULL) { DrawFormatString(150, 300, GetColor(255, 255, 255), "セーブできません\n"); } else { DrawFormatString(150, 300, GetColor(255, 255, 255), "buf_Cntセーブ成功:%d\n", buf_cnt); for (int i = 0; i < buf_cnt; i++) { DrawFormatString(600,i*21, GetColor(255, 255, 255), "buf_xセーブ成功:%f\n", buf_x[i]); } fwrite(&buf_cnt, sizeof(int), 1, fp); fwrite(&buf_x, sizeof(float), buf_cnt, fp); fwrite(&buf_y, sizeof(float), buf_cnt, fp); fclose(fp); } } if (load == 1) { //x座標の保存 fopen_s(&fp, "test.dat", "rb"); if (fp == NULL) { DrawFormatString(0, 340, GetColor(255, 255, 255), "ロードできません\n"); } else { DrawFormatString(0, 340, GetColor(255, 255, 255), "ロード成功\n"); fread(&buf_cnt2, sizeof(int), 1, fp);//buf_cnt分読み出し fread(&buf_x2, sizeof(float), buf_cnt, fp); fread(&buf_y2, sizeof(float), buf_cnt, fp); fclose(fp); lineCnt = buf_cnt2; for (int i = 0; i < buf_cnt; i++) { bline[i].BlackLineX = buf_x2[i]; bline[i].BlackLineY = buf_y2[i]; DrawFormatString(300, i * 21, GetColor(255, 255, 255), "buf_xセーブ成功:%f\n", bline[i].BlackLineX); } } }
actorbug

2021/06/27 12:17

手元に環境が無いので目視のみの確認となりますが、問題はなさそうです。
matsu0o

2021/06/27 14:15

非常に分かりやすい説明でした。ありがとうございます 追加の質問で申し訳ないのですが今の自分のコードだと描いた線が保存されずにロードしても画面に何も映りません。このコードだと、また別にセーブ、ロードする物を追加する必要があるのでしょうか、、? 個人的には for(int i=0;i<lineCnt;i++){DrawLine(bline[i - 1].BlackLineX, bline[i - 1].BlackLineY, bline[i].BlackLineX, bline[i].BlackLineY, bline[i].color,6);} これで線を描画しているので lineCnt,bline[i]BlackLineX,bline[i]BlackLineY この3つをセーブ、ロードすればできると思ったんですが、、、
actorbug

2021/06/27 20:02

申し訳ないですが、これ以上のことは私ではわかりかねます。 私より詳しい他の方に回答してもらってください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問