我一直在使用Turbo C ++(:/)并遇到了问题。
我正在制作一个需要文件处理的学校项目。我的程序接受用户的输入并给出4个选项:
CLASS DEFINITION:
#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);
------------- ----------- EDIT
我将班级成员的WhozCraig和qPCR4vir的建议和单独的函数用于将自己插入到文件中。事情是我再次陷入障碍.. 输出显示所有数据成员,而它应该只显示sr no。和播放列表名称。我认为输入或输出是错误的。 代码:
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播放列表,而是打印2609.Second Playlist。
谢谢你们,大家好。 我真的很感激,你认真帮助了我很多! @WhozCraig和@qPCRvir:谢谢大家,感谢您的回答和建议。我真的很感激。 :)
答案 0 :(得分:2)
此代码存在多个问题,您可以考虑退回并重新考虑您真正想要做的事情。
对于初学者来说,循环读取逻辑在其项目读取大小方面存在根本缺陷。您应该每次迭代读取一个项目,或者只读取整个数组一次,然后枚举数组以查找可用于新播放列表的项目。问题的核心是:
fileo.read((char*)&wmp[h],sizeof(wmp));
这会从当前文件位置开始读取项目的大小,直至整个 wmp
数组的大小,并将结果存储在内存中的位置h
数组中的wmp
元素存在(wmp+h
)。我真诚地希望您看到,如果h
永远大于0,这可能会读取过去数组的末尾并进入未定义的行为。
如果这是唯一改变的,那就应该这样做:
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();
但老实说,正确的方法是 不 以上。例如,将播放列表写入磁盘的正确方法是:
playlist::favorite
类的成员函数,给定二进制流对象,可以将本身写入该输出流。playlist
类的成员函数,给定二进制流对象,可以编写本身,以及当前最喜欢的歌曲数,然后每个< / em>最喜欢的歌曲使用上面(1)中的喜欢 - 作家成员函数。类似的逻辑将用于读取文件。
playlist::favorite
的成员函数,给定输入二进制流对象引用,可以从流中读取本身。playlist
的成员函数,给定一个输入二进制流对象引用,可以自己读取,以及它最喜欢的数量,然后对于每个收藏,调用上面(1)中的收藏读者这是做到这一点的众多方法中的一种,但是相当合乎逻辑且很好地链接。考虑一下。即便如此,也存在平台可移植性问题,但除非您将播放列表文件从一个平台共享到另一个平台,否则不应将其视为一个问题。
答案 1 :(得分: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的所有想法,只是为了使代码更简单,而不是解决你的最终问题。