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------------- 终于完成了!输入,输出,删除都很好。只有一个小问题是“sr”正在获取内存值而不是序列号。文件中的值。因此,不是将第二个播放列表打印为 2.Second Playlist,而是打印 2609.Second Playlist。

谢谢你们,你们所有人。我真的很感激,你真的帮了我很多!@WhozCraig 和@qPCRvir:谢谢你们的回答和建议。我真的很感激。:)

4

2 回答 2

2

这段代码存在多个问题,以至于您可能会考虑退后一步,重新考虑您真正想做的事情。

对于初学者来说,循环读取逻辑在其项目读取大小方面存在根本缺陷。您应该每次迭代读取一个项目,或者只读取整个数组一次,然后枚举该数组以查找可用于新播放列表的项目。问题的核心是这样的:

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

这会从当前文件位置开始读取最大为整个 wmp 数组大小的项目,并将结果存储在内存中数组中h第 th 个元素所在的位置wmpwmp+h)。我真诚地希望您看到,如果大于h0 ,可能会读取到数组末尾并进入未定义的行为。

如果这是唯一改变的事情,那么应该这样做:

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)中的收藏阅读器。
  3. 编写一个知道如何打开输入二进制文件流对象的全局函数,然后读取其播放列表计数,然后为每个播放列表调用上面(2)中编写的播放列表读取器。

只是这样做的众多方法之一,但相当合乎逻辑,并且链接得很好。考虑一下。即使这样,也存在平台可移植性问题,但除非您将播放列表文件从一个平台共享到另一个平台,否则这不应该成为问题。

于 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 回答