I am having trouble reading in data from a file. The data file store the information of albums and its respective track info

eg
1234 //this is id number
Scarlets Walk //album name
Tori Amos //artist
24 //price
2 //stock
Pop //genre
Track A //track name
10 30 //track length in mins and secs
Track B
5 0
Track C
3 15

Each album can have up to 20 tracks, however im just using a data file with 3 per album for initial testing. The problem i am having is that i cannot get my read in function (which worked when there was no track data) to read in the album and its respective track data.
Here is the relevant code. I am not sure how to create the loops since different albums would have different amounts of tracks.

struct tracklist
{
	char trackName[32];	
	int trackMins;
	int trackSecs;
};

struct albums
{
	char idNo[10];
	char albumName[32];
	char artistName[32];
	tracklist tracks;
	float price;
	int stock;
	char genre[32];
};

albums cdstock[Arraysize];

int YourLoadDB()
{

	int i = 0;
	ins.open("CDSample.txt", ios::in);

	if(ins.good())
	{
		while ((ins.good()) && (i < Arraysize))
		{
			ins >> cdstock[i].idNo;
			ins.clear();
			ins.ignore(100,'\n');
			ins.getline(cdstock[i].albumName, 256);
			ins.getline(cdstock[i].artistName, 256);	
			ins >> cdstock[i].price;
			ins >> cdstock[i].stock;
			ins.clear();
			ins.ignore(100,'\n');
			ins.getline(cdstock[i].genre, 256);
			ins.clear();
			ins.ignore(100,'\n');
			for (int x = 0; x < 3; x++)
			{
				ins.getline(cdstock[x].tracks.trackName, 256);
				ins.clear();
				ins.ignore(100,'\n');
				ins >> cdstock[x].tracks.trackMins >> cdstock[x].tracks.trackSecs;
				ins.clear();
				ins.ignore(100,'\n');
			}			
			i++;
		}
	}
	else
	{
		cout << "File does not exist!" << endl;	
	}
	numrec = i-1;
	cout << "The amount of records loaded is: " << numrec << endl;
	return i;
	
	
	ins.close();
}

First thing, you should really rename tracklist to track since that struct is only storing info about one track.

The main problem is that your album structure only can store one track. You will need to alter your album structure to be able to store a list of tracks that is variable in size. The easiest way to do this is to use an STL container such as vector. Instead of having:

struct tracklist {
   char trackName[32];
   int trackMins;
   int trackSecs;
};

struct albums {
   char idNo[10];
   char albumName[32];
   char artistName[32];
   tracklist tracks;
   float price;
   int stock;
   char genre[32];
};

Do something like this:

struct track {
   char trackName[32];
   int trackMins;
   int trackSecs;
};

struct albums {
   char idNo[10];
   char albumName[32];
   char artistName[32];
   vector<struct track> tracklist;
   float price;
   int stock;
   char genre[32];
};

Now the problem becomes how can you determine how many tracks are in each album? Either you can store the number of tracks for that specific album in the file above the track listings so you know how many times to loop, or if you can assume track names don't start with numbers, once you read in a track name starting with a number, you know it is really just the id of the next album. I would go with the first option myself if you can change the format of the file.

If you haven't used vectors before, check out: http://www.cplusplus.com/reference/stl/vector/

I can change the format of the file to store each track and its duration on a cd. I cannot use a vector. How would i go about implementing the second option?

Seing as an album can store a max of 20 tracks, would i be able to make the instance of the track list struct to have the size 20, then read in, until i hit a number?

If you can't use a vector, then yes, you could have an array of struct track of size 20, but then you must store the number of tracks in the album information as well.

so replace:

vector<struct track> tracklist;

with:

struct track tracklist[20];

i tried that (i left the struct names the same for the time being)

struct tracklist tracks[20];

but i get this error

error: request for member ‘trackName’ in ‘cdstock[x].albums::tracks’, which is of non-class type ‘tracklist [20]’

Yes you are going to have to change the code in your loop a bit to reflect the changes in the structure.

For example, if x is counting to the number of tracks in the album, replace:

ins.getline(cdstock[x].tracks.trackName, 256);

with:

ins.getline( cdstock[i].tracks[x].trackName, 256 );

You want to alter the ith cd, but the xth track.

Thanx, that worked :). However how would i be able to make the read in loop when it stops at a number, so i dont have an array of 20 with no data in some of the array. How could i do this?

If you dont want to waste space in your array then you need to use something like a vector which I already recommended. If this is for an assignment or something and you're "not allowed" to use any STL containers (like vector or list), then you would have to make your own implementation of a linked list. This is not a trivial task if the concept is new to you, however it is worth learning.

Basically, STL containers, and linked lists, among other structures, dynamically allocate memory for items as you insert into them. The basic concept for a linked list is that it keeps a pointer to the first time, and the first item has a pointer to the second item, and so on. So you can just keep creating items and linking them on to the end whenever you want.

IMAO, a restructure of the data file should be done. Don't rely on a number to tell you that you're done with the tracks. I know many songs that start with a number:
76 Trombones
8675309

for example.

Add to each line a type value that tells you what the line contains. Each line should have a value for ease of programming. Also, if some information is not available, it won't mess up the program.

1,1234 //this is id number
2,Scarlets Walk //album name
3,Tori Amos //artist
4,24 //price
5,2 //stock
6,Pop //genre
7,Track A //track name
8,10 30 //track length in mins and secs
7,Track B
8,5 0
7,Track C
8,3 15
1,1254 //this is id number
etc.

Now, when you don't read a 7 or 8 line you know you're done with the tracks.

Having all those numbers in front and parsing each line is much more difficult than just having the number of tracks listed after the genre.

I sorted the read in problem by adding a track count variable since i can modify the data file which is being read in to suit my program. So now the track count is read in, then the loop sequence is determined by the amount of tracks per album. Here is what i did, however it only reads in the first record then the first track.

int YourLoadDB()
{

	int i = 0;
	ins.open("CDSample.txt", ios::in);

	if(ins.good())
	{
		while ((ins.good()) && (!ins.eof()) && i < Arraysize)
		{
			ins >> cdstock[i].idNo;
			ins.clear();
			ins.ignore(100,'\n');
			ins.getline(cdstock[i].albumName, 32);
			ins.getline(cdstock[i].artistName, 32);
			ins.clear();	
			ins >> cdstock[i].price;
			ins >> cdstock[i].stock;
			ins.clear();
			ins.ignore(100,'\n');
			ins.getline(cdstock[i].genre, 32);
			ins.clear();
			ins >> cdstock[i].trackCount;
			
			for (int x = 0; x < cdstock[i].trackCount; x++)
			{
				ins.clear();
				ins.getline(cdstock[i].tracks[x].trackName, 32);
				ins.clear();
				ins >> cdstock[i].tracks[x].trackMins >> cdstock[i].tracks[x].trackSecs;
				ins.clear();
			}			
			i++;
		}
		
	}
	else
	{
		cout << "File does not exist!" << endl;	
	}
	numrec = i;
	cout << "The amount of records loaded is: " << numrec << endl;
	return i;
	
	
	ins.close();
}

The above code loops 2(The index (i) has a value of 2 at the end of the read in) times to read in both albums and there respective tracks, however when i attempt to search through the array to print the data, only the first album and the first track print out.

Any ideas why the loop is doing this?

At first glance I don't see the problem. I do have a question though - where is cdstock coming from? It's not a parameter to your function. If it is a global variable, you should really change that...

Anyway, it might even be a problem with your testing code where you are printing the albums, can you post that?

The cdstock is part of a struct thats in global. Its in global so all the different functions can access the data.

Here's 2 different print functions which i am using

void YourDisplayCD()
{
	char number[32];

	cout << "Enter the id or album name number: ";
	cin.clear();
	cin.ignore(100,'\n');
	cin.getline(number, 32);

	for(int i = 0; i < numrec; i++)
	{
		if(strcmp(cdstock[i].idNo, number) == 0 )
		{
			cout << cdstock[i].idNo << endl;;
			cout << cdstock[i].albumName << endl;
			cout << cdstock[i].artistName << endl;			
			cout << cdstock[i].price << endl;
			cout << cdstock[i].stock << endl;
			cout << cdstock[i].genre << endl;
			for(int x = 1; x < cdstock[i].trackCount; x++)
			{	
				cout << cdstock[i].tracks[x].trackName << endl;
				cout << cdstock[i].tracks[x].trackMins << " " << cdstock[i].tracks[x].trackSecs;				
			}
		}
		else if(strcmp(cdstock[i].albumName, number) == 0 )
		{
			cout << cdstock[i].idNo << endl;;
			cout << cdstock[i].albumName << endl;
			cout << cdstock[i].artistName << endl;	
			cout << cdstock[i].price << endl;
			cout << cdstock[i].stock << endl;
			cout << cdstock[i].genre << endl;
			for(int x = 1; x < cdstock[i].trackCount; x++)
			{	
				cout << cdstock[i].tracks[x].trackName << endl;
				cout << cdstock[i].tracks[x].trackMins << " " << cdstock[i].tracks[x].trackSecs;
			}
		}
	}
	return;
	cout << "CD does not exist"<<endl;

}

void YourList()
{
	char search[32];

	cout << "Enter artist name or album genre"  << endl;
	cin.clear();
	cin.ignore(100,'\n');
	cin.getline(search, 32);

	for(int i = 0; i < numrec; i++)
	{
		if(strcasecmp(cdstock[i].artistName, search) == 0 )
		{
			cout << cdstock[i].idNo << endl;;
			cout << cdstock[i].albumName << endl;
			cout << cdstock[i].artistName << endl;		
			cout << cdstock[i].price << endl;
			cout << cdstock[i].stock << endl;
			cout << cdstock[i].genre << endl;
			for(int x = 1; x < cdstock[i].trackCount; x++)
			{	
				cout << cdstock[i].tracks[x].trackName << endl;
				cout << cdstock[i].tracks[x].trackMins << " " << cdstock[i].tracks[x].trackSecs;				
			}
			
		}
		else if (strcasecmp(cdstock[i].genre, search) == 0 )
		{
			cout << cdstock[i].idNo << endl;;
			cout << cdstock[i].albumName << endl;
			cout << cdstock[i].artistName << endl;		
			cout << cdstock[i].price << endl;
			cout << cdstock[i].stock << endl;
			cout << cdstock[i].genre << endl;
			for(int x = 1; x < cdstock[i].trackCount; x++)
			{	
				cout << cdstock[i].tracks[x].trackName << endl;
				cout << cdstock[i].tracks[x].trackMins << " " << cdstock[i].tracks[x].trackSecs;
				return;				
			}
		}
	}
	
	
}
This article has been dead for over six months. Start a new discussion instead.