0

ファイル処理でC++文字列を使用するにはどうすればよいですか?プライベートデータメンバーの1つとしてC++文字列を持つクラスを作成しましたが、現時点で操作しておらず、コンストラクターでデフォルト値で初期化されていても、ファイルからの読み取り中にエラーが発生しました。ファイルへの書き込み中は問題ありません。代わりにC文字列を使用すれば問題なく動作しますが、使用したくありません。これを解決する方法はありますか?

class budget 
{      
     float balance;      
     string due_name,loan_name;              //string objects
     int  year,month;     
     float due_pay,loan_given;    

     public:                 
     budget()     
     {      
          balance=0;
          month=1;        
          due_name="NO BODY";              //default values
          loan_name="SAFE";   
          year=0;             
          balance = 0;      
          due_pay=0;        
          loan_given=0;      
     }
      .
      .
      .
 };

void read_balance()                //PROBLEM AFTER ENTERING THIS FUNCTION      
{          
     system("cls");        
     budget b;     
     ifstream f1;     
     f1.open("balance.dat",ios::in|ios::binary);     
     while(f1.read((char*)&b,sizeof(b)))     
     { b.show_data();       
     }     
     system("cls");        
     cout<<"No More Records To Display!!";     
     getch();     
     f1.close();       
} 
4

3 に答える 3

2

文字列はnon-POD data-type. 読み取り/書き込み関数で文字列を読み書きすることはできません。

basic_istream<charT,traits>& read(char_type* s, streamsize n);

30 効果: フォーマットされていない入力関数として動作します (27.7.2.3、パラグラフ 1 で説明されているように)。セントリー オブジェクトを構築した後、!good() が setstate(failbit) を呼び出すと、例外がスローされて返される場合があります。 それ以外の場合は、文字を抽出し、最初の要素が s.323 で指定されている配列の連続した場所に格納します。文字は、次のいずれかが発生するまで抽出および格納されます。 — n 文字が格納されます。— 入力シーケンスでファイルの終わりが発生した場合 (この場合、関数は setstate(failbit | eofbit) を呼び出し、ios_base::failure (27.5.5.4) をスローする可能性があります)。31 戻り値: *これ。

メンバーの配置方法については何もありませんstd::string。見るか使うboost::serialiationhttp: / 、この配列のデータを読み取り、文字列を作成します。しかし、ブーストを使用する方が良いです。

于 2012-07-29T20:07:25.117 に答える
0

これを解決する最も簡単な方法は、そのクラスでC++文字列を使用しないことです。保存する各文字列の最大長を計算し、1バイト長いchar配列を作成します(0ターミネータを考慮に入れるため)。これで、シリアル化などを気にすることなく、そのクラスをバイナリとして読み書きできます。

それを望まない場合は、クラスでiostream :: read()を使用することはできません。ストリームに対して読み取り/書き込みを行うメンバー関数が必要になります。これがシリアル化の目的です...しかし、ブーストの複雑さは必要ありません。基本的に、次のようなことを行います。

// Read with no error checking :-S
istream& budget::read( istream& s )
{
    s.read( (char*)&balance, sizeof(balance) );
    s.read( (char*)&year, sizeof(year) );
    s.read( (char*)&month, sizeof(month) );
    s.read( (char*)&due_pay, sizeof(due_pay) );
    s.read( (char*)&loan_given, sizeof(loan_given) );

    size_t length;
    char *tempstr;

    // Read due_name
    s.read( (char*)&length, sizeof(length) );
    tempstr = new char[length];
    s.read( tempstr, length );
    due_name.assign(tempstr, length);
    delete [] tempstr;

    // Read loan_name
    s.read( (char*)&length, sizeof(length) );
    tempstr = new char[length];
    s.read( tempstr, length );
    loan_name.assign(tempstr, length);
    delete [] tempstr;

    return s;
}

ostream& budget::write( ostream& s )
{
    // etc...
}

上記で、最初にサイズ値を書き込み、その後にその数の文字を書き込むことによって文字列をシリアル化したことに注意してください。

于 2012-07-30T00:25:02.620 に答える
0

クラスの予算の文字列メンバー (due_name,loan_name) を読み取っている間、コードは文字通りバイトごとに埋めていきます。float と int には意味がありますが、文字列には機能しません。

文字列は「無制限」の量のテキストを保持するように設計されているため、そのコンストラクター、コピー コンストラクター、連結などは、テキストを格納し、必要に応じて拡張する (そして破棄時に削除する) ために、実際のメモリ部分を確実に割り当てる必要があります。この方法でディスクから文字列を埋めると、文字列オブジェクト内に無効なポインターが作成されます (テキストを含む実際のメモリを指しているわけではありません)。実際には、この方法で実際に読み取られるテキストはまったくありません。

于 2012-07-29T23:17:48.530 に答える