1

Turbo C ++(:/)をしばらく使用していて、問題が発生しました。

私はファイル処理を必要とする学校のプロジェクトを作成しています。私のプログラムはユーザーからの入力を受け取り、4つのオプションを提供します。

  1. 既存のファイルを上書き/変更する
  2. ファイルを作成する
  3. ファイルを削除する
  4. すべてのファイルを表示

クラス定義:

#define max 20
class playlist{
    static int ctr;
    int sr;
    char name[max];
    class favsong
    {

        char song[max];
        char genre[max];
        char artist[max];
        int rating;

    public:
        void playin()
        {
            cout<<"Enter song name"<<endl;
            gets(song);
            cout<<"Enter genre"<<endl;
            gets(genre);
            cout<<"Enter artist"<<endl;
            gets(artist);


            cout<<"Enter rating (out of 5)"<<endl;
            cin>>rating;

        }
        void playout()
        {
            cout<<"\nSong:";
            puts(song);
            cout<<"Artist:";
            puts(artist);
            cout<<"Genre:";
            puts(genre);
            cout<<"rating:"<<rating<<endl;
        }
        favsong()
        {
            rating=0;
            strcpy(song,"Not Assigned");
            strcpy(genre,"Not Assigned");
            strcpy(artist,"Not Assigned");
        }
        ~favsong(){}
    }favs[5];

public:
    void input();
    void output();

    void showname()
    {
        puts(name);
    }

    int givesr()
    {
        return sr;
    }

    int existp (int n)
    {
        if(n==sr)
            return 1;
        else
            return 0;
    }

    playlist()//constructor
    {
        strcpy(name,"Default playlist");
        sr=ctr;
        ctr++;
    }

    ~playlist(){}

    int existp(char arr[])
    {
        if(strcmp(name,arr)==0)
            return 1;
        else
            return 0;
    }

}wmp[max],obj;
int playlist::ctr=1;

void playlist::input()
{
    cout<<"Enter playlist name"<<endl;
    gets(name);
    for(int i=0;i<5;i++)
        favs[i].playin();
    cout<<"Input complete"<<endl;

}

void playlist::output()
{
    cout<<"Playlist no"<<sr;
    for(int i=0;i<5;i++)
        favs[i].playout();
    cout<<"\noutput complete"<<endl;
}

プレイリストを作成しようとすると、ランタイムエラーが発生します。コード:

case 2: cout<<"Creating new playlist...press enter to continue"<<endl;
getch();
obj.input();
h=0;
while(!file.eof()){
    fileo.read((char*)&wmp[h],sizeof(wmp));
    if(wmp[h].existp("Default playlist")){ //int existp(int*a) compares the object's
                                           // name to the string"Default Playlist
        pos=fileo.tellg();
        file.seekp(-pos,ios::cur);
        file.write((char*)&wmp,sizeof(wmp) );
    }
    h++;
}
break;

私はこれを3日間続けています。とてもシンプルに見えましたが、ここで何が問題なのかわかりません。

また、ファイルは実行のたびにワイプされ続けます。コード:

ofstream file("playlist.dat",ios::out|ios::app|ios::noreplace|ios::binary|ios::ate);
ifstream fileo("playlist.dat",ios::in|ios::binary);

- - - - - - -編集 - - - - - -

私はWhozCraigとqPCR4virのアドバイスを利用し、クラスのメンバーが自分自身をファイルに挿入するための個別の関数を使用しました。再び障害に遭遇しました。出力にはすべてのデータメンバーが表示されていますが、sr番号のみが表示されているはずです。とプレイリスト名。入力または出力が間違っていると思います。コード:

void existp()  //function to show all existing playlists in the file.
            {  ifstream tmp("playlist.dat",ios::in|ios::binary);
                tmp.seekg(ios::beg);
                tmp.read((char*)&wmp,sizeof(wmp));
                for(int i=0;i<max;i++){
                cout<<wmp[i].givesr();
                wmp[i].showname();
           }
           tmp.close();
            }


    void fileput(){  //fileput and fileget are functions to put inner class member in //file
    ofstream file("Playlist.dat",ios::out|ios::app|ios::nocreate|ios::binary);
    file<<song<<endl<<artist<<endl<<genre<<endl<<rating<<endl;
file.close();
            }

void fileget(){
ifstream file("Playlist.dat",ios::in|ios::binary);
file.getline(song,max,'\n');
    file.getline(artist,max,'\n');
file.getline(genre,max,'\n');
file>>rating;
file.close();
        }

//外部クラスのデータメンバーをファイルに入れる外部クラス関数の関数定義

void playput(long int pos){
ofstream file("Playlist.dat",ios::out|ios::app|ios::nocreate|ios::binary);
file.seekp(pos,ios::beg);
file<<name<<"\n";
for(int i=0;i<5;i++)
favs[i].fileput();
file.close();
}

void playget(long int pos){
ifstream file("Playlist.dat",ios::in|ios::binary);
file.seekg(pos,ios::beg);
file.getline(name,max,'\n');
for(int i=0;i<5;i++)
favs[i].fileget();
file.close();
     }

-------------編集2-------------ついに完了しました!入力、出力、削除は順調に進んでいます。わずかな問題の1つは、「sr」がシリアル番号ではなくメモリ値を取得していることです。ファイルからの値。したがって、2番目のプレイリストを2.Secondプレイリストとして印刷する代わりに、2609.Secondプレイリストを印刷します。

皆さん、ありがとうございました。私は本当に感謝しています、あなたは私をたくさん助けてくれました!@WhozCraigと@qPCRvir:皆さんの回答とアドバイスに感謝します。本当に感謝しています。:)

4

2 に答える 2

2

このコードには複数の問題があり、立ち止まって実際にやろうとしていることを再考することを検討する可能性があります。

手始めに、ループ読み取りロジックは、アイテム読み取りサイズに根本的な欠陥があります。反復ごとに1つのアイテムを読み取るか、配列全体を1回読み取るだけで、配列を列挙して、新しいプレイリストで使用できるアイテムを探します。問題の核心はこれです:

fileo.read((char*)&wmp[h],sizeof(wmp));

これにより、現在のファイル位置から開始して配列全体のサイズまで アイテムが読み取られ、結果が配列内のth要素が存在するメモリ内の場所に格納されます()。が0より大きい場合、配列の終わりを超えて未定義の動作になる可能性があることをご理解いただければ幸いです。wmp hwmpwmp+hh

これが唯一の変更である場合は、次のように実行する必要があります。

fileo.read((char*)&wmp[h],sizeof(wmp[h]));

しかし、これは氷山の一角にすぎません。ループ自体には根本的な欠陥があり、固定ファイルサイズも固定されています。ディスクからプレイリスト配列を読み取る(またはディスクに書き込む)際に反復ループが発生する理由はありません。次のような配列全体を一括書き込みするだけです。

ofstream ofs(filename, ios::out|ios::binary|ios::trunc);
ofs.write((char*)&wmp, sizeof(wmp));
ofs.close();

同様の偏見を持ってそれを読んでください:

ifstream ifs(filename, ios::in|ios::binary)
ifs.read((char*)&wmp, sizeof(wmp));
ifs.close();

しかし、正直なところ、これを行う正しい方法は上記ではありません。たとえば、プレイリストをディスクに書き込む正しい方法は次のとおりです。

  1. playlist::favoriteバイナリストリームオブジェクトが与えられると、その出力ストリームに自分自身を書き込むことができるクラスのメンバー関数を記述します。
  2. playlistバイナリストリームオブジェクトが与えられた場合に、それ自体と現在のお気に入りの曲の数を書き込むことができるクラスのメンバー関数を記述し、次に上記(1)のfavorite-writerメンバー関数を使用して各お気に入りの曲を記述します。
  3. バイナリ出力モードでファイル(名前を指定)を開く方法を知っているグローバル関数を記述し、占有されているプレイリストエントリの数を書き出し、占有されているエントリごとに、上記(2)のプレイリストライターメンバー関数を呼び出します。

同様のロジックがファイルの読み取りに使用されます。

  1. そのメンバー関数を記述して、入力バイナリストリームオブジェクト参照が与えられると、ストリームからそれ自体playlist::favoriteを読み取ることができます。
  2. そのメンバー関数をplaylist記述して、入力バイナリストリームオブジェクト参照を指定すると、それ自体とそのお気に入りのカウントを読み取ることができます。次に、お気に入りごとに、上記の(1)からfavorite-readerを呼び出します。
  3. 入力バイナリファイルストリームオブジェクトを開き、そのプレイリストカウントを読み取り、プレイリストごとに上記(2)で記述したプレイリストリーダーを呼び出す方法を知っているグローバル関数を記述します。

これを行う多くの方法の1つにすぎませんが、かなり論理的で、うまく連鎖しています。考えてみてください。これでもプラットフォームの移植性の問題がありますが、プレイリストファイルをあるプラットフォームから次のプラットフォームに共有しない限り、問題として表面化することはありません。

于 2013-01-26T21:23:46.837 に答える
0

私は他の答えに触れたくありませんが、今は他の問題があり、すべてを台無しにすることはできません。私はデバグすることはできません。これは完全なコードではなく、アイデアを説明しようとする私にとってより良い方法にすぎません。

#include <iostream> 
#include <fstream> 
using namespace std;

#define max 20

class playlist
{   static int ctr;
    int sr;
    char name[max];
    class favsong
    {   char song[max];
        char genre[max];
        char artist[max];
        int rating;
      public:
        void playin()
        {   cout<<"Enter song name"<<endl;            gets(song);
            cout<<"Enter genre"<<endl;                gets(genre);
            cout<<"Enter artist"<<endl;               gets(artist);
            cout<<"Enter rating (out of 5)"<<endl;    cin>>rating;
        }
        void playout()
        {   cout<<"\nSong:";            puts(song);
            cout<<"Artist:";            puts(artist);
            cout<<"Genre:";             puts(genre);
            cout<<"rating:"         <<rating    <<endl;
        }
        void fileput(ofstream &file)   //  (Point 1:) put (get) inner class member (favsong) in file
        {   // txt variant  
            file<<song<<endl<<artist<<endl<<genre<<endl<<rating<<endl;
            // or the pure binary variant:
            //file.write ((char*)this, sizeof(favsong));
        }
        void fileput()   //  put (get) inner class member (favsong) in file
        {   ofstream file("Playlist.dat",ios::out|ios::app|ios::nocreate|ios::binary);
            file<<song<<endl<<artist<<endl<<genre<<endl<<rating<<endl;
            file.close();
        }
        void fileget(ifstream &file)
        {   // txt variant
            file.getline(song,  max,'\n');
            file.getline(artist,max,'\n');
            file.getline(genre, max,'\n');
            file>>rating;
        }
        void fileget()
        {
            ifstream file("Playlist.dat",ios::in|ios::binary);
            file.getline(song,  max,'\n');  
            file.getline(artist,max,'\n');
            file.getline(genre, max,'\n');
            file>>rating;
            file.close();
        }
        favsong()
        {   rating=0;
            strcpy(song,  "Not Assigned");
            strcpy(genre, "Not Assigned");
            strcpy(artist,"Not Assigned");
        }
        ~favsong(){}
    }favs[5];

 public:
    void input();
    void output();
    void playput(ofstream &file)        //  (Point 2:) puts outer class data members in file
    {
        // txt
        file<<name<<"\n";
        // or one "pure" binary variant
        //file.write (name, sizeof(name));

        for(int i=0;i<5;i++)
            favs[i].fileput(file);  // equal for both bin or txt

        // or one pure binary variant to put the entery list at once:
        //file.write ((char*)this, sizeof(playlist));
    }
    void playput( ofstream &file, long int pos)     //puts outer class data members in file
    {
        file.seekp(pos,ios::beg);
        playput(file);              // equal for both bin or txt
    }
    void playput(long int pos)      //puts outer class data members in file
    {
        ofstream file("Playlist.dat",ios::out|ios::app|ios::nocreate|ios::binary);
        file.seekp(pos,ios::beg);
        playput(file);
        file.close();
    }

    // now write the equivalent for get.....
    void playget(long int pos)
    {
        ifstream file("Playlist.dat",ios::in|ios::binary);
        file.seekg(pos,ios::beg);
        file.getline(name,max,'\n');
        for(int i=0;i<5;i++)
        favs[i].fileget(file);
        file.close();
     }
    void showname()     {        puts(name);    }
    int givesr()        {        return sr;     }
    int existp (int n)  {        return (n==sr) ?   1 : 0;    }

    playlist()//constructor
    {   strcpy(name,"Default playlist");
        sr=ctr;
        ctr++;
    }
    ~playlist(){}
    int existp(char arr[])  {    return (strcmp(name,arr)==0)  ?   1 : 0;    }

}wmp[max],obj;

int playlist::ctr=1;

void playlist::input()
{   cout<<"Enter playlist name"<<endl;
    gets(name);
    for(int i=0;i<5;i++)
        favs[i].playin();
    cout<<"Input complete"<<endl;
}

void playlist::output()
{   cout<<"Playlist no"<<sr;
    for(int i=0;i<5;i++)
        favs[i].playout();
    cout<<"\noutput complete"<<endl;
}

void existp()  //function to show all existing playlists in the file.
{  ifstream tmp("playlist.dat",ios::in|ios::binary);
    tmp.seekg(ios::beg);
    tmp.read((char*)&wmp,sizeof(wmp));
    for(int i=0;i<max;i++)
    {   cout<<wmp[i].givesr();
        wmp[i].showname();
    }
    tmp.close();
}
void save_playlist(const char *file_name)  //    (Point 3:)
{   ofstream file(file_name,ios::out|ios::binary);
    for(int i=0;i<max;i++)
        wmp[i].playput (file);

    // or one pure binary variant to put all list at once:
    //file.write((char*)&wmp,sizeof(wmp));

    file.close();
}
void load_playlist(const char *file_name)  //    (Point 3:)
{   ifstream file(file_name,ios::in|ios::binary);
    file.seekg(ios::beg);
    for(int i=0;i<max;i++)
        wmp[i].playget(file);

    // or one pure binary variant to get all list at once:
    //file.read((char*)&wmp,sizeof(wmp));

    file.close();
}

次に、リストを操作します。

void using_play_list (const char *file_name)
{
    /*case 2:*/ cout<<"Creating new playlist...press enter to continue"<<endl;
    getch();
    obj.input();

    load_playlist(file_name);

    // now test and modify wmp as need.

    int h=0;
    while(h<max){
        if(wmp[h].existp("Default playlist"))
        {   //int existp(int*a) compares the object's
            // name to the string"Default Playlist
            //    ????????????
        }
        h++;
    }

    save_playlist(file_name);


    break;
}

これは@WhozCraigからのすべてのアイデアであり、コードを単純化するためのものであり、最終的な問題を解決するためのものではありません。

于 2013-01-27T22:04:38.423 に答える