2012-05-08 14 views
1

だから、私はこれまで何度もアップしてきました。しかし、ここのコードは最初の実行時にのみ機能します。つまり、約4つのオプションがあるメニューがあるため、最初に選択されたものだけが機能します。 do whileループが起動してメニューが再び表示されると、選択したメニューに関係なく、メニューが再び表示されます。私はdo whileループを分析しましたが、それに問題はないと確信しています。私は最近、File I/Oについて学び始めたので、忘れたかもしれません。どんな助けでも本当に感謝しています。ありがとう。ここでファイルI/Oコード(C++)

はコードです:

Phonebook.h

#include <iostream> 
#include <fstream> 
#include <cstdlib> 
#include <string> 

using namespace std; 

class Phone 
{ 
public: 
void display_phonebook(ifstream& in_stream);// phonebook is the text file 
void display_backup(string a[], int size);// backup copy is a string array 
void datacopy(ifstream& in_stream, string a[]);// to copy the phonebook to the array 
int numberOfLines(ifstream& in_stream);// to check number of lines in the text file 
}; 

Phonebook.cpp

#include <iostream> 
#include <fstream> 
#include <cstdlib> 
#include <string> 
#include "Phonebook.h" 

using namespace std; 

void Phone::datacopy(ifstream& in_stream, string a[]) 
{ 
int i=0; 
while(in_stream.good()) 
{ 
    string line; 
    getline(in_stream, line); 
    a[i]=line; 
    i++; 
} 
int s=i; 
for(int x=0;x<s;x++) 
{ 
    cout<<a[x]<<endl; 
} 
} 


int Phone::numberOfLines(ifstream& in_stream) 
{ 
int count=0; 
while(!in_stream.eof()) 
{ 
    string line; 
    getline(in_stream, line); 
    count++; 
} 
return count; 
} 

void Phone::display_phonebook(ifstream& in_stream) 
{ 
while(!in_stream.eof()) 
{ 
    string line; 
    getline(in_stream, line); 
    cout<<line<<endl; 
} 
} 

void Phone::display_backup(string a[], int size) 
{ 
for(int i=0;i<size;i++) 
{ 
    cout<<a[i]<<endl; 
} 
cout<<endl; 
} 

main.cppに

#include <iostream> 
#include <fstream> 
#include <cstdlib> 
#include <string> 
#include "Phonebook.h" 

using namespace std; 

int main() 
{ 
Phone p; 
int size=0; 
ifstream fin; 
ofstream fout; 
char file[50], ch; 
string backup[50]; 
int flag=0; 
do 
{ 
    cout<<"Enter the name of the file: "<<endl; 
    cin>>file; 
    fin.open(file); 
    cout<<endl; 
    if(fin.fail()) 
    { 
     cout<<"File not found!"<<endl<<endl; 
     cout<<"Try Again? (Y/N)"<<endl; 
     cin>>ch; 
     if(ch=='N' || ch=='n') 
     { 
      cout<<"Terminating..."<<endl; 
      system("PAUSE"); 
      exit(1); 
     } 
    } 
    else 
    { 
     flag=1; 
    } 
} 
while((ch=='Y' || ch=='y') && flag==0); 
cout<<"Success! File Opened"<<endl<<endl; 
int choice; 
do 
{ 
    cout<<"1 - Display phonebook"<<endl; 
    cout<<"2 - Display backup copy"<<endl; 
    cout<<"3 - Update backup copy"<<endl; 
    cout<<"4 - Exit"<<endl; 
    cout<<"Enter your choice: "; 
    cin>>choice; 
    if(choice==1) 
    { 
     p.display_phonebook(fin); 
    } 
    else if(choice==2) 
    { 
     size=p.numberOfLines(fin); 
     p.display_backup(backup, size); 
    } 
    else if(choice==3) 
    { 
     p.datacopy(fin, backup); 
    } 
} 
while(choice!=4); 
fin.close(); 
fout.close(); 
system("PAUSE"); 
return 0; 
} 
+4

一般に、このような膨大なコードダンプは、スタックオーバーフローの助けを得る方法ではありません。確かに、これを問題を示す最小限の例にすることができます。そして、あなたがそれをやっている間にあなたがそれを解決すれば、あなたのために良い! – dmckee

+0

あなたはループを苦しんでいますか?私はあなたのコードで5を数えました。 – jrok

+0

@Stencil @jrok:彼は文字通り '' 1 - Display phonebook ''を使ってdo whileループを意味します。直接的な原因はストリームが悪い状態になったことですが、すぐには明らかではありませんが、それは悪い状態です。 –

答えて

3

1)これは多くのコードを投稿するべきではありません。最小限の完全な例を投稿する必要があります。つまり、悪い振る舞いを生み出しながら、できるだけコードを振り下ろしてください。最終的にバグが明らかになるか、私たちが噛み合うためにもっと小さくて簡単なものに着くでしょう。

2)無関係なコードをすべて削除するには余裕がありますか?問題はありません、最初にそれを書いてはいけません。小規模から始まり、あらゆる段階でテストしてください。は、動作しないコードに決して追加しません。。問題を発見することなくコードを大きくすることは決してあってはいけません。

3)

void Phone::display_phonebook(ifstream& in_stream) 
{ 
    while(!in_stream.eof()) 
    { 
     string line; 
     getline(in_stream, line); 
     cout<<line<<endl; 
    } 
} 

これは、ファイル一度の内容を表示します。その後、ファイルの終わりにファイルのストリームがあります。これは、本の裏表紙を見つめているようです。この関数をもう一度呼び出すと、それ以上のことはありません。ファイルの内容を変数に格納するか、ストリームを閉じて再オープンする(または巻き戻しを行う必要がありますが、これは高度な手法であり、推奨されません)。

+0

これは一度正しく表示されないことがあります。行の読み取りを試み、読み取りが成功したかどうかにかかわらず、結果を使用します。ループは 'std :: string line;でなければなりません。 while(std :: getline(in_stream、line)){std :: cout << line << std :: endl; } ' –

+0

+1ステップ2は非常に重要です。インクリメンタルテストFTWによるインクリメンタルな変更 – AJG85

+0

@JamesKanze、あなたはそうだけど、この全体の機能は、とにかに改造または廃止されなければならない。コード内には他にも問題があるかもしれません。私はちょうど最も明白な誤動作の原因を指摘していた。 – Beta

3

したがって、関数にifstreamを送信してgetlineを呼び出すと、「バッファ」が拡張されます。だから、バッファをもう一度開かずにその行を読み返すことはできません。これを考慮に入れてコードを再編成するか、または表示中に再読み込みするのではなく、ファイルからデータを保存する必要があります。

+0

ええと...あなたはおそらく正しいと思います。私はこのアプローチを試してみるつもりです。大変ありがとう。 – Pulkit2692

0

コードには多くの問題があります。

あなたのコードが一度「うまくいった」理由は、最初に 完了にファイルを読み込み、入力をファイルの最後に残すためです。したがって、 の読み取りは失敗します。ファイルを完全にメモリ の前に読み込んだ後、画像を渡します(std::vector<std::string>を に、さまざまな機能を使用するか、またはstd::ifstreamオブジェクト をローカル変数として作成する必要があります。 std::ifstreamオブジェクトがメインループ内にある場合)、エラーが発生していない場合は、 がエラーをクリアし、各 が機能する前にストリームの先頭に移動する必要があります。

ループの制御条件として、in_stream.good()または !in_stream.eof()を使用していることもあります。そして、 std::getlineによって読み取られた文字列を使用してstd::getlineが成功したことを確認せずに、 で少なくともdatacopydisplay_phonebookになります。 通常、これにより最終行が2回処理されます。 std::istream::good()は役に立たない関数です。あなたが失敗を検出した後、 は面白くてです。あなたのループを書く への正しい方法は次のとおりです。 入力ファイルは、より多くの50行を持っている場合

std::string line; 
while (std::getline(in_stream, line)) { 
    // ... 
} 

Phone::datacopyは未定義の動作をしている(おそらくクラッシュします)。ここでstd::vector<std::string> を使用し、関数の先頭でそれをクリアしてから、読み込んだ行ごとに push_backを呼び出します。

また、コマンドを読むときに何らかのエラー処理が必要になることがあります。 と入力すると、例えば'a'と入力すると、無限ループに入ります。 私はおそらくstd::getlineを対話型入力にも使用しますが、 行を別々に構文解析します。このようにして、実際の入力は に入りません。これはユーザーが迷惑メールを入力した場合にクリアする必要があります。 (そして、 彼は"Display phonebook"のようなものを入力した場合、あなたが入力中の過剰のすべての文字を取り払う約2つの 心配はありません。)

を最後に、あなたはどのoperaator>>で、ユーザークラスLineを定義した場合 はgetlineを使用し、ほとんどの関数は std::copyへの1回の呼び出しに還元され、std::istream_iterator<Line>を使用します。

ああ、if/else ifチェーンの代わりにswitchを使用できます。

+0

私はそれを稼働させることができましたが、私は将来これらの点に留意しています。感謝します。 – Pulkit2692

0

皆さん、ありがとうございます。しかし、ええ、問題は、コントロールが2番目の関数に渡されたときにファイルの最後に入力ストリームが滞留していたことです。最も簡単な修正は、ストリームがファイルの最後に達した後にストリームを閉じて再オープンすることでした。これが私が採用したものです。また、より良いコーダーになるのを手伝ってくれる人たちのことをたくさん知りました(私は願っています)。また、コードのいくつかの例外処理(間違いなく@James Kanze)を見ていきます。申し訳ありません。