2017-10-26 9 views
-2

データファイルの処理を理解するために、C++で小さなコードを記述しました。プログラムは、エントリを受け取り、.datファイルに書き込んで、特定のエントリを検索することで構成されています。これまでのところ、書き込み機能のみが動作しており、読み出し機能と検索機能がセグメンテーション・フォルト・エラーを示しています。何がうまくいかないの?データファイル処理におけるセグメンテーションフォールトの問題

#include<iostream> 
#include<string> 
#include<fstream> 
#include<stdlib.h> 
using namespace std; 
class data_base 
{ 
    string name; 
    long int no; 
public: 
void input() 
{ 
cout<<"\nEnter name:"; 
cin>>name; 
cout<<"Enter ph number:"; 
cin>>no; 
} 
void display() 
{ 
cout<<name<<"\t"<<no; 
} 
string retname() 
{ 
return name; 
} 
long int retno() 
{ 
return no; 
} 
}; 
void display_all() 
{ 
    data_base d; 
    fstream in; 
    in.open("database.dat",ios::in|ios::binary); 
    if(!in.is_open()) 
    cout<<"Error opening file"; 
    else{ 
    while(in.read((char *)&d,sizeof(d))) 
    { 
     d.display(); 
    } 
    } 
    in.close(); 
} 
void search_name() 
{ 
    data_base d; 
    fstream in; 
    string s; 
    in.open("database.dat",ios::in|ios::binary); 
    if(!in.is_open()) 
    cout<<"Error opening file"; 
    else{ 
     cout<<"\nEnter name to be searched:"; 
     cin>>s; 
     while (in.read((char *) &d,sizeof(d))) { 
      if(s==d.retname()) 
     { 
      d.display(); 
     } 
     } 
     } 
    in.close(); 
} 
void search_no() 
{ 
    data_base d; 
    fstream in; 
    long int l; 
    in.open("database.dat",ios::in|ios::binary); 
    if(!in.is_open()) 
     cout<<"Error opening file"; 
    else{ 
     cout<<"\nEnter number to be searched:"; 
     cin>>l; 
     while (in.read((char *) &d,sizeof(d))) 
     { 
      if(l==d.retno()) 
      { 
       d.display(); 
      } 
     } 

    } 
     in.close(); 
} 
int main() 
{ 
    int ch; 
    fstream file; 
    data_base d,e; 
    string s; 
    while(1) 
    { 
    cout<<"1.Add entry\n2.Search by name\n3.Search by 
    number\n4.Display all entries\5.Exit"<<endl; 
    cin>>ch; 
    switch (ch) { 
     case 1: d.input(); 
       file.open("database.dat",ios::out|ios::app|ios::binary); 
       if(!file.is_open()) 
       cout<<"Error opening file"; 
       else 
       { 
       file.write((char *)&d,sizeof(d)); 
       cout<<"Entry added!"<<endl; 
       } 
       file.close(); 
       break; 
     case 2:search_name(); 
       break; 
     case 3:search_no(); 
       break; 

     case 4:display_all(); 
       break; 
     case 5: exit(0); 
     } 
    } 
} 
+1

'std :: string'(またはその他の単純な型)では' read'と 'write'を使うことはできません。文字列には、ファイルに書き込むときに失われるヒープデータへのポインタが含まれています。 [シリアライズ](https://isocpp.org/wiki/faq/serialization)を読んでみてください。 –

+0

うわー、ありがとう。コードは、 'std :: string'を文字配列に変更した後に機能しました。 –

答えて

1
class data_base 
{ 
    string name; 
    ... 
} 
... 
data_base d; 
... 
file.write((char *)&d,sizeof(d)); 

あなたはすでにここに運命づけされています。 std::string構造体の内部にポインタがあります。このポインタをchar配列として再解釈すると、一連の文字列が得られます。それをファイルに保存し、しばらくしてから読んでください。

その時点で、新たに読み取られたdata_base変数は、の正確なというバイナリ表現を以前のものと同じように持ちます。しかし今やstd::stringの内部ポインタはもはや有効なメモリアドレスを指していないので、segfaultです。

segfaultingは実際には良いことに注意してください。いくつかの悪いケースでは、メモリアドレスは有効ですが、完全に無関係な(ランダムな)データを指しています。それは非常にのバグでしょう。

これは最初から間違っています。 シリアル化/逆シリアル化のためにchar*とキャストしないでください。適切なシリアライズ手法を使用してください。構造をxml、json、google protobufに変換するか、何かカスタムを考え出してください。生の記憶を再解釈しないでください。 struct内にポインタがない場合でも、バイナリ表現はコンパイラ、os、cpuに依存します。

関連する問題