• ベストアンサー

ファイル読込時に構造体の文字列ポインタに割当てたいと

ファイル読込時に構造体の文字列ポインタに割当てたいと思っています。 (new 演算子を使用します。) 文字列の長さが不定です。 どうすれば、文字列の長さを知ることができますか? 以下のようなところまでは作れましたが、 困っています。 void loaddata()のfscanf関数の部分です。 ほかにも関数の void outputdata() void deletedata() がありますが、長いので省略しました。 ********************************************************** #include<stdio.h> #include<string.h> class data { public: struct basic { char *name; int age; struct basic *next; }; private: struct basic *base; struct basic *base_top; int cnt; public: data::data() { cnt=0; } void inputdata(char *name,int age) { if(cnt==0) { base=new basic; base_top=base; base->age=age; int len=strlen(name); base->name=new char[len+1]; strcpy(base->name,name); cnt++; } else { base->next=new basic; base=base->next; base->age=age; int len=strlen(name); base->name=new char[len+1]; strcpy(base->name,name); cnt++; } } void savedata() { base=base_top; FILE *fp; fp=fopen("dat.txt","w"); for(int i=0;i<cnt;i++) { fprintf(fp,"%s\t%d\n",base->name,base->age); base=base->next; } fclose(fp); } void loaddata() { if(cnt!=0){deletedata();} cnt=0; FILE *fp; fp=fopen("dat.txt","r"); while(1) { fscanf(fp,"%s\t%d\n",base->name,base->age); } } };

質問者が選んだベストアンサー

  • ベストアンサー
  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.2

 簡易な方法は、#1さんの通りです。  面倒な(でも、まっとう)方法も、考え方だけ書いておきます。  scanf系の関数に関しては、必要なメモリー領域を知る方法はありません。  fgetcを使って、一文字ずつ読み込み、これを文字列に足していく形をとるのがとりあえず簡単でしょう。  バッファにする文字列の領域管理に関しては、これだけで一つのクラスを作ることになるくらい面倒な代物です。C++ですから、標準クラスにstringというクラスがあります。この際、使っちゃってください。  それを前提にすれば、ある程度は、簡単に組めます。  可変長の文字列を一つ読み込むルーチンを作るとすると次のような感じでしょうか・・・。 #include <string> ・・・ char *input_string(FILE *fp) { char buff_c; string buff; while ( (buff_c=fgetc(fp)) != EOF ) { if (buff_c == '\t' || buff_c == '\n') break; buff += buff_c ; } char *ret = (char*) malloc(buff.length()+1); strcpy(ret, buff.str_c()); return ret; }  ここで、buff+=buff_c;の行は、string型のbuffの末尾に、文字を一つ追加してくれる演算子です。 (buff = buff+buff_c; の表記も可能です。)  この時に、内部のバッファの容量管理をstringクラスがしてくれるので、このような簡潔な表記が可能です。  また、ループ後のコピー処理は、元のプログラムで、char*の型で処理をするためにつけておきました。関数の宣言をstring input_string(FILE *fp)としてもかまわないのであれば、そのまま、buffを返すことができます。  ところで、このstringクラスですが、実際に自分で作るとなると、かなり大変です。どうやれば、こんなクラスが作れるかを知りたければ、C++の教本を見ると、習作としてstringクラスを作成している本は多いので探してみられると良い勉強にはなると思います。

thulala
質問者

お礼

ありがとうございます。 やり方を少し変えました。 文字列の長さを書きこみじに一緒に書きました。 freadで、長さ・文字列とすることで何とかなりました。 ただ、新たなエラーが出ましたので、 困っています。 ありがとうございました。

thulala
質問者

補足

ありがとうございます。 その方法は機会があればやってみます、 というよりこれが完成すればやります。

その他の回答 (1)

  • nyan5504
  • ベストアンサー率42% (6/14)
回答No.1

一般的に、scanf系の関数はメモリ領域の長さ限界に対するフォローがなく、バグの原因になりやすいので使わない方がよいとされています。 今回のケースで完璧に可変長文字列に対応するには、fgetsなどを使って可変長バッファに読み込んでいくしかありません。 ただ、それは非常に面倒なので、練習のためのプログラムであればchar[1024]など、非常に大きなバッファにfscanfで読み込み、必要なメモリを確保し、コピーするという方法が良くとられます。 今回の場合であれば char buf[1024]; buf[0] = '\0'; fscanf(fp,"%s\t%ld\n", buf, &base->age); base->name = new char[strlen(buf)]; strcpy(base->name, buf); で良いでしょう。

thulala
質問者

お礼

ありがとうございます。 やり方を少し変えました。 文字列の長さを書きこみじに一緒に書きました。 freadで、長さ・文字列とすることで何とかなりました。 ただ、新たなエラーが出ましたので、 困っています。 ありがとうございました。

関連するQ&A