#include <iostream>
using namespace std;
const int testmax=10;
typedef struct {
int a1,a2;
}test_t;
test_t test[testmax];
inline void Save(test_t test[]){
FILE *fp ;
fp = fopen( "test.dat" , "wb" ) ;
if( fp == NULL )
return ;
fwrite(test,sizeof(test) , 1 , fp ) ;
// ファイルを閉じる
fclose( fp ) ;
}
inline void Load(test_t test[]){
FILE *fp ;
fp = fopen("test.dat","rb") ;
if(fp==NULL){
}
else
{
//データの読み込み
fread(test, sizeof(test) , 1 , fp ) ;
// ファイルを閉じる
fclose( fp ) ;
}
}
int main(void){
for(int i=0;i<testmax;i++){
test[i].a1=i;
test[i].a2=10-i;
}
Save(test);
for(int i=0;i<testmax;i++){
test[i].a1=0;
test[i].a2=0;
}
Load(test);
for(int i=0;i<testmax;i++)
cout<<test[i].a2<<"\n";
cin>>test[0].a2;
return 0;
}
配列を用いた構造体をfwriteで書き込みたい
-
bonbo
配列を用いた構造体をfwriteで書き込みたい
配列を用いた構造体をfwriteでバイナリファイルに書き込み、それを読み込もうと思い、以下のようなプログラムをつくったのですが、うまく動作してくれません(読み込めていないのか書き込めていないのかわからないが、すべて0になっている)。どうすればいいのでしょうか。
Re: 配列を用いた構造体をfwriteで書き込みたい
fwrite() と fread() の第3引数が1である理由を教えてください。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: 配列を用いた構造体をfwriteで書き込みたい
第3引数がどうのこうの言う前に、コンパイルが通らないっぽいですね。
# 当方だけかな?きっとそうなんでしょう。
# 当方だけかな?きっとそうなんでしょう。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: 配列を用いた構造体をfwriteで書き込みたい
Save関数とLoad関数の中のtestはtest_t型の変数へのポインタであり、
サイズは(Ideoneでは)4バイトになります。
サイズは(Ideoneでは)4バイトになります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: 配列を用いた構造体をfwriteで書き込みたい
fread/fwriteで読み書きしているのは、関数の引数であるtest_tへのポインタ型の一時変数testです。
なので外部宣言されたtest配列には影響しません。
(訂正)
#思いっきり勘違い。<俺
Load/Save関数内のtestは、関数の引数であるtest_tへのポインタ型の一時変数testが対象です。
なのでsizeofではtest_tへのポインタ型のサイズが返ります。
というのは、みけCATさんが書いているとおり。
なので外部宣言されたtest配列には影響しません。
(訂正)
#思いっきり勘違い。<俺
Load/Save関数内のtestは、関数の引数であるtest_tへのポインタ型の一時変数testが対象です。
なのでsizeofではtest_tへのポインタ型のサイズが返ります。
というのは、みけCATさんが書いているとおり。
最後に編集したユーザー ISLe on 2012年8月19日(日) 23:26 [ 編集 2 回目 ]
-
bonbo
Re: 配列を用いた構造体をfwriteで書き込みたい
>boxさん
ありがとうございます。
>fwrite() と fread() の第3引数が1である理由を教えてください。
ミスです…というかよくわかっていませんでした…
この場合、a1の要素10こ、とa2の要素10こで20とすべきだ。ということでしょうか…間違っていたらません…
>みけCATさん
ありがとうございます。
>Save関数とLoad関数の中のtestはtest_t型の変数へのポインタであり、
サイズは(Ideoneでは)4バイトになります。
つまり関数内ではバイト数が変わるので、そのままではsizeof()の中には入れられないということでしょうか…
ありがとうございます。
>fwrite() と fread() の第3引数が1である理由を教えてください。
ミスです…というかよくわかっていませんでした…
この場合、a1の要素10こ、とa2の要素10こで20とすべきだ。ということでしょうか…間違っていたらません…
>みけCATさん
ありがとうございます。
>Save関数とLoad関数の中のtestはtest_t型の変数へのポインタであり、
サイズは(Ideoneでは)4バイトになります。
つまり関数内ではバイト数が変わるので、そのままではsizeof()の中には入れられないということでしょうか…
-
bonbo
Re: 配列を用いた構造体をfwriteで書き込みたい
一応第三引数を増やしたら書き込めるようにはなりました。いろいろ実験してみたところfwriteの仕組みがわかったので解決にしておきます。みなさんありがとうございました。また何かありましたらよろしくお願いします。
-
bonbo
Re: 配列を用いた構造体をfwriteで書き込みたい
忘れてました…
#include <iostream>
using namespace std;
const int testmax=10;
typedef struct {
int a1,a2;
}test_t;
test_t test[testmax];
inline void Save(test_t test[]){
FILE *fp ;
fp = fopen( "test.dat" , "wb" ) ;
if( fp == NULL )
return ;
fwrite(test,sizeof(test) , 20 , fp ) ;
// ファイルを閉じる
fclose( fp ) ;
}
inline void Load(test_t test[]){
FILE *fp ;
// オープンできなかったらファイルが無いとみなし
//消す
fp = fopen("test.dat","rb") ;
if(fp==NULL){
}
else
{
//データの読み込み
fread(test, sizeof(test) , 20 , fp ) ;
// ファイルを閉じる
fclose( fp ) ;
}
}
int main(void){
for(int i=0;i<testmax;i++){
test[i].a1=i;
test[i].a2=10-i;
}
Save(test);
for(int i=0;i<testmax;i++){
test[i].a1=0;
test[i].a2=0;
}
Load(test);
for(int i=0;i<testmax;i++)
cout<<test[i].a2<<"\n";
for(int i=0;i<testmax;i++)
cout<<test[i].a1<<"\n";
cin>>test[0].a2;
return 0;
}
Re: 配列を用いた構造体をfwriteで書き込みたい
グローバルの変数名と関数の引数の名前が同じだから分かりにくいのです。bonbo さんが書きました:つまり関数内ではバイト数が変わるので、そのままではsizeof()の中には入れられないということでしょうか…
グローバル変数名 test を g_test とかにしてみましょう。
また配列を関数の引数として渡すなら、個数も渡すべきでしょう。
// 略
test_t g_test[testmax]; // 変数名はなるべく同じ名前にしない!!
inline void Save(test_t test[], int kosu)
{
// 略
// 変数名でなく型名をsizeofする
fwrite(test,sizeof(test_t), kosu, fp );
// 略
}
inline void Load(test_t test[], int kosu)
{
// 略
// 変数名でなく型名をsizeofする
fread(test,sizeof(test_t), kosu, fp );
// 略
}
// main関数内では
// Save(g_test, testmax);
// Load(g_test, testmax);オフトピック
fread/fwriteの第3引数を20にしてて、sizeofに渡すのも変数のままなので、本当に理解しているの?とこちらでは思うのですが。bonbo さんが書きました:いろいろ実験してみたところfwriteの仕組みがわかったので解決にしておきます
最後に編集したユーザー へにっくす on 2012年8月19日(日) 23:28 [ 編集 3 回目 ]
written by へにっくす
-
bonbo
Re: 配列を用いた構造体をfwriteで書き込みたい
>へにっくすさん
ありがとうございます。
>変数名はなるべく同じ名前にしない!!
>変数名でなく型名をsizeofする
>また配列を関数の引数として渡すなら、個数も渡すべきでしょう。
なるほど…
全然理解してないですね…親切なアドバイスありがとうございます…
>boxさん
>第3引数を20にした理由は何ですか?
この場合、a1の要素10こ、とa2の要素10こで20とすべきだ。と思ったからです。間違っていたら指摘していただけると嬉しいです
ありがとうございます。
>変数名はなるべく同じ名前にしない!!
>変数名でなく型名をsizeofする
>また配列を関数の引数として渡すなら、個数も渡すべきでしょう。
なるほど…
全然理解してないですね…親切なアドバイスありがとうございます…
>boxさん
>第3引数を20にした理由は何ですか?
この場合、a1の要素10こ、とa2の要素10こで20とすべきだ。と思ったからです。間違っていたら指摘していただけると嬉しいです
Re: 配列を用いた構造体をfwriteで書き込みたい
構造体のメンバーが増えたら、その都度30にしたり40にしたりするんですか?bonbo さんが書きました: この場合、a1の要素10こ、とa2の要素10こで20とすべきだ。と思ったからです。間違っていたら指摘していただけると嬉しいです
何だか効率的ではないような気がします。
test_t 型(メンバーの構成は知ったことではない)が testmax 個あると考える方が、
より自然ではないのかな、という気がします。配列test[] の定義がそういう風になってますよね。
その配列をまるっと読み書きするのですから、test[] の先頭アドレスから、
test_t 型の大きさの要素を testmax 個読み書きする、というコードの方が、
改変が少なくてすむような気がします。
最後に編集したユーザー box on 2012年8月19日(日) 23:51 [ 編集 1 回目 ]
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
-
bonbo
Re: 配列を用いた構造体をfwriteで書き込みたい
boxさん
>test_t 型(メンバーの内容は変わりうる)が testmax 個あると考える方が、
より自然ではないのかな、という気がします。
つまり…メンバーの数をmenbernumとでもおいて
20のところをtestmax*menbernumとすればいいということでしょうか。
そのほうがきれいですね。
アドバイスありがとうございます。
>test_t 型(メンバーの内容は変わりうる)が testmax 個あると考える方が、
より自然ではないのかな、という気がします。
つまり…メンバーの数をmenbernumとでもおいて
20のところをtestmax*menbernumとすればいいということでしょうか。
そのほうがきれいですね。
アドバイスありがとうございます。
Re: 配列を用いた構造体をfwriteで書き込みたい
membernum という変数を導入する必要は、ありません。bonbo さんが書きました: つまり…メンバーの数をmenbernumとでもおいて
20のところをtestmax*menbernumとすればいいということでしょうか。
sizeof(test_t) という、構造体の大きさが testmax 個ある、ということです。
仮に、構造体の中に、double型とかchar型とかのメンバーを追加したとしても、
「え~とint型が2個でdouble型が何個でchar型が何バイトだから…」などという計算を自分でしなくても、
構造体そのもの大きさはいつだって sizeof(test_t) で求まる、というのがポイントです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
-
bonbo
Re: 配列を用いた構造体をfwriteで書き込みたい
>boxさん
>sizeof(test_t) という、構造体の大きさが testmax 個ある
fwrite(test,sizeof(test_t) , sizeof(test_t)*testmax, fp ) ;
でしょうか…
>sizeof(test_t) という、構造体の大きさが testmax 個ある
fwrite(test,sizeof(test_t) , sizeof(test_t)*testmax, fp ) ;
でしょうか…
-
bonbo
Re: 配列を用いた構造体をfwriteで書き込みたい
>仮に、構造体の中に、double型とかchar型とかのメンバーを追加したとしても、
「え~とint型が2個でdouble型が何個でchar型が何バイトだから…」などという計算を自分でしなくても、
構造体そのもの大きさはいつだって sizeof(test_t) で求まる、というのがポイントです。
なるほど!ありがとうございます!
「え~とint型が2個でdouble型が何個でchar型が何バイトだから…」などという計算を自分でしなくても、
構造体そのもの大きさはいつだって sizeof(test_t) で求まる、というのがポイントです。
なるほど!ありがとうございます!
Re: 配列を用いた構造体をfwriteで書き込みたい
それだと、bonbo さんが書きました: >sizeof(test_t) という、構造体の大きさが testmax 個ある
fwrite(test,sizeof(test_t) , sizeof(test_t)*testmax, fp ) ;
でしょうか…
sizeof(test_t) という大きさの領域が
sizeof(test_t)*testmax 個ある、
ということになってしまいそうです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。
プログラムは思ったとおりには動かない。書いたとおりに動く。
Re: 配列を用いた構造体をfwriteで書き込みたい
メンバのサイズの合計と構造体のサイズが等しいとは限りませんしね。box さんが書きました:「え~とint型が2個でdouble型が何個でchar型が何バイトだから…」などという計算を自分でしなくても、
構造体そのもの大きさはいつだって sizeof(test_t) で求まる、というのがポイントです。
-
かずま
Re: 配列を用いた構造体をfwriteで書き込みたい
Save や Load の中に 20 なんて書いてはダメです。次のようにすれば、
配列の要素数が変わっても、testmax の値の変更一か所だけで済みます。
さらに、C++ だったら、FILE よりも <fstream> でしょう。
配列の要素数が変わっても、testmax の値の変更一か所だけで済みます。
#include <iostream>
#include <cstdio>
using namespace std;
const int testmax = 10;
struct test_t {
int a1, a2;
};
test_t test[testmax];
inline void Save(const test_t *test, size_t size)
{
FILE *fp = fopen("test.dat", "wb");
if (fp == NULL) return;
fwrite(test, sizeof(test_t), size, fp);
fclose(fp);
}
inline void Load(test_t *test, size_t size)
{
FILE *fp = fopen("test.dat", "rb");
if (fp == NULL) return;
fread(test, sizeof(test_t), size, fp);
fclose(fp);
}
int main()
{
for (int i = 0; i < testmax; i++) {
test[i].a1 = i;
test[i].a2 = 10-i;
}
Save(test, testmax);
for (int i = 0; i < testmax; i++) {
test[i].a1 = 0;
test[i].a2 = 0;
}
Load(test, testmax);
for (int i = 0; i < testmax; i++)
cout << test[i].a2 << "\n";
for (int i = 0; i < testmax; i++)
cout << test[i].a1 << "\n";
return 0;
}
#include <fstream>
using namespace std;
inline void Save(const test_t *test, size_t size)
{
ofstream ofs("test.dat", ios::binary);
if (ofs) ofs.write((const char *)test, sizeof(test_t) * size);
}
inline void Load(test_t *test, size_t size)
{
ifstream ifs("test.dat", ios::binary);
if (ifs) ifs.read((char *)test, sizeof(test_t) * size);
}