Ok, I have been busting tail trying to get this simple project done. Lesson learned is do not take a break from course work during the summer, my lack of fundamentals at this moment is tear me apart. I am determined to finish this project ahead of time to finish the rest of my other course work.

The current project broken down shortly

Using previous teachings of arrays, structs, reference parameters, pointers we are to construct a program doing the following

Using a array of structs, we have a file "song.dat" and the text inside of the file looks like such

Title
Artist
Genre
Track Time

This will count as one item we can not have more than 10 items

upon start up we must read from a "song.dat" file and then provide the user with a choice of options but Ill start off with what I got

I created a function -load_file which should read from song.dat and then when later called clear the current array and read from a file of the users choice

Then I will print out the array

This is the code I have...tis very messy/poor programming habits...sorry

My main problems, it seems to read from "song.dat" at execution
and when I load the next file i THINK the old array clears but it just prints out 0 0 0 0

Edit: I added i = 0; after the file opens in the load function and read correctly from the next file

But I am sure there is more efficent ways than mine

In song.dat there are 4 items the next file of my choice there is 3

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

const int MAX = 10; 

struct music{
       string title, artist, genre;
       int iTrackTime; 
       };


int load_file(char* file, music song[MAX], int i);
void print_song(music song[MAX], int i);

int main()
{
    int choice;
    int  j;
    int i;
    music song[MAX];
    
    char new_file[256];
    
    
    i = load_file("song.dat", song, i); //Read from song.dat file upon execution of program
    
    do{
          cout<<endl;
          cout<<"Load a new file of songs - 1\n";
          cout<<"Print current array of songs - 2\n";
          cout<<"Enter a number for a task: ";
          cin>>choice; 
          cout<<endl;
          
          switch(choice){
                         
                         case 1:
                                
                                cout<<"Enter the new file of songs: ";
                                cin>>new_file;
                                load_file(new_file, song, i);
                         
                                break;
                         case 2:
                                 print_song(song, i);
                         default:
                                 break;
                         }
          }while(choice != 10);
          
    system("Pause");
    return 0;
}

int load_file(char* file, music song[MAX], int i)
{
               
     string dummy;
     ifstream fin; 
     
     if(i !=0){
                for(int j=0; j<i; j++){
                        song[j].title.clear();
                        song[j].artist.clear();
                        song[j].genre.clear();
                        song[j].iTrackTime = 0;
                                      }
                }
                
    fin.open(file);
     
     while(!fin.eof() && i<MAX){
                       getline(fin,song[i].title);
                       getline(fin,song[i].artist);
                       getline(fin,song[i].genre);
                       getline(fin,dummy); //Read the track time as a string so it grabs the newline
                       song[i].iTrackTime = atoi(dummy.c_str());//Now conver the string into a integer
                       i++;//A count of items in file
                       }
     fin.close();
     return(i);
}

void print_song(music song[MAX], int i)
{
    for(int j=0; j<i; j++)
    {
             cout<<song[j].title
             <<song[j].artist
             <<song[j].genre
             <<song[j].iTrackTime<<endl;
             }
}

Also when I change the order the variable i and j the program crashes

Before

int main()
{
    int choice;
    int  j;
    int i;
    music song[MAX];

After

int main()
{
    int choice;
    int  i;
    int j;
    music song[MAX];

The program crashes...
-_-'

Recommended Answers

All 9 Replies

My main problems, it seems to read from "song.dat" at execution
and when I load the next file i THINK the old array clears but it just prints out 0 0 0 0

Edit: I added i = 0; after the file opens in the load function and read correctly from the next file

See red. You need to confirm, not guess. These are not good variable names. What do they stand for? Name them descriptively.

int load_file(char* file, music song[MAX], int i);
void print_song(music song[MAX], int i);

I just saw your edit. Not sure where you put i = 0 exactly, but it was a problem, and depending on where exactly you put it, it could still be a problem. All variables must be initialized before you use them in a formula or as a comparison.

Your first task is to make sure you read in the data correctly in a wide variety of circumstances, and throw everything you can at it that it is supposed to catch (i.e. empty file, files with exactly 10 records, files with fewer, files with more, bad filename, etc.). Make sure it reads in correctly, including the data and the number of songs. Until that's right, you can go no further.

While "i" is the counter of the number of items in the file, so it can fill the array correctly, hence the while statement in the load function, So i believe this function is working in a sense just could use some ethical coding habits to clean it up

I place a "i = 0" after the fin.open(file); in the load function it seemed to fix it, I just dont understand why the order of i and j in the int main makes the program crash

While "i" is the counter of the number of items in the file, so it can fill the array correctly, hence the while statement in the load function, So i believe this function is working in a sense just could use some ethical coding habits to clean it up

You're passing i FROM main TO the function and it isn't being passed by reference (and it isn't initialized, so you're passing a garbage value to a function. You could be passing 879124 for all you know. Do you have 879124 songs?).

I just dont understand why the order of i and j in the int main makes the program crash

It's just dumb luck. Switching it made it so it didn't crash THIS time. Next time it might. Look at your function. Say i was 879124 (random made-up large value) before you passed it to the function:

int load_file(char* file, music song[MAX], int i)
{
               
     string dummy;
     ifstream fin; 
     
     if(i !=0){
                for(int j=0; j<i; j++){
                        song[j].title.clear();
                        song[j].artist.clear();
                        song[j].genre.clear();
                        song[j].iTrackTime = 0;
                                      }
                }

j ranges from 0 to 879,123. Does your song[] array go that high? If not, seg fault. And again, either rename i to something meaningful or don't pass it.

I think I improved my code a bit better, it just seems the function inside load
doesnt clear the array correctly

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

struct music
{
       string title;
       string artist;
       string genre;
       int time ;
};

int read(char* file, music songs[10] , int lCount = 0);
void print(music songs[10], int lCount);
int main()
{
    music songs[10];
    int j = 0, lCount = 0, choice = 0;
    char file[256];
    
    lCount = read("song.dat",songs);
    
   do
   {
    cout<<"Enter choice: ";
    cin>>choice;
    
    switch(choice)
    {
                  case 1: 
                          cout<<"Enter new file: ";
                          cin>>file;
                          read(file, songs, lCount);
                          break;
                  case 2:
                         print(songs, lCount);
                         break;
                  default:
                          break;
    }
    }while(choice != 10);
   
    
    system("Pause");
    return 0;
}
    
int read(char *file, music songs[10], int lCount)
{
    
    
    ifstream fin;
    string string;
    file[256];
    
    if(lCount != 0)
    {
         for(int i=0; i < lCount; i++)
         {
                  songs[i].title.clear();
                  songs[i].artist.clear();
                  songs[i].genre.clear();
                  songs[i].time = 0;
         }
    }
    
   
    
    
    fin.open(file);
    
    int i = 0;
    
    while(!fin.eof() && i < 10)
    {                
        getline(fin,songs[i].title);
        getline(fin,songs[i].artist);
        getline(fin,songs[i].genre);
        getline(fin,string);
        songs[i].time = atoi(string.c_str());
        i++;
    }
    
    fin.close();
    return(i);
}

void print(music songs[10], int lCount)
{
     
      for(int j = 0; j < lCount; j++)
    {
            cout<<songs[j].title
                <<songs[j].artist
                <<songs[j].genre
                <<songs[j].time<<endl;
    }
}

lCount still holds the value of the orignial fill read in my case which is 4, says the next file holds 3

it does

Title
Artist
Genre
Time

Title
Artist
Genre
Time

Title
Artist
Genre
Time

0

First things first. If you haven't already done so, you need to check to make sure that your INITIAL read is correct. That means adding some debugging statements (take them out later when it works - see red):

int read(char *file, music songs[10], int lCount)
{
    
    
    ifstream fin;
    string string;
    file[256];
    
    if(lCount != 0)
    {
         for(int i=0; i < lCount; i++)
         {
                  songs[i].title.clear();
                  songs[i].artist.clear();
                  songs[i].genre.clear();
                  songs[i].time = 0;
         }
    }
    
   
    
    
    fin.open(file);
    
    int i = 0;
    
    while(!fin.eof() && i < 10)
    {                
        getline(fin,songs[i].title);
        getline(fin,songs[i].artist);
        getline(fin,songs[i].genre);
        getline(fin,string);
        songs[i].time = atoi(string.c_str());
        i++;
    }

    cout << "There are " << i << " songs.  Here they are:\n";
    print (songs, i);
    
    fin.close();
    return(i);
}

If that doesn't match what is in your file exactly for your INITIAL read, stop and debug that function.

I added the debug statement it seems that array is adding 1 more than read

so I start with 4 items
the read 3

it says count is 4 but displays 3 items and the last time once more

I added the debug statement it seems that array is adding 1 more than read

so I start with 4 items
the read 3

it says count is 4 but displays 3 items and the last time once more

?????

You need to be a little more precise with your language. Please explain exactly what you've done and what is happening more clearly.

I'm guessing the actual song.dat file has three songs, but it's trying to read four songs, probably due to improper use of the eof () function.

Note that end-of-file when using getline is NOT detected when the last non-white-space character is read from the file. You have to eat up any remaining newline characters and even try to read PAST that before the end-of-file is detected. So it's probably happening inside of your while loop. Stick some more debugging statements in there.

while(!fin.eof() && i < 10)
    {                
        getline(fin,songs[i].title);
        if (fin.eof ())
            cout << "End of file reached after reading title\n";
        getline(fin,songs[i].artist);
        if (fin.eof ())
            cout << "End of file reached after reading artist\n";
        getline(fin,songs[i].genre);
        if (fin.eof ())
            cout << "End of file reached after reading genre\n";
        getline(fin,string);
        if (fin.eof ())
            cout << "End of file reached after reading time\n";

        songs[i].time = atoi(string.c_str());
        i++;
    }

My guess is that you'll find that the end of the file is reached in the middle of your while loop, not at the end, so you're not really reading anything in for that last song.

The moral is that you need to be really careful when using eof (). Before incrementing i, you need to test and make sure that you have actually read in a valid song. Either test for eof () before incrementing i or test for blank values when you read them in, but the way you have it now, you only check for it at the top of your while loop, and that isn't sufficient in this case.

Ok, Ill explain a bit more clear

The orginial file it reads on start up has 4 items...1 item looks like this

Title
Artist
Song
Time

Now when I choose the option to load a new file it loads the new file but seems to add 1 to the iterator "i"

Say my new file has 3 items, it will say the value of i is 4 when I added your debug statement and the output will look like such

Title, Artist, genre, time
Title, Artist, genre, time
Title, Artist, genre, time
time << repeats the last time read

The debug says the end of file is reached when time is read so it seems to be looping correctly, but somewhere the value of i its adding 1 to the true value of the items

Ok, Ill explain a bit more clear

The orginial file it reads on start up has 4 items...1 item looks like this

Title
Artist
Song
Time

Now when I choose the option to load a new file it loads the new file but seems to add 1 to the iterator "i"

Say my new file has 3 items, it will say the value of i is 4 when I added your debug statement and the output will look like such

Title, Artist, genre, time
Title, Artist, genre, time
Title, Artist, genre, time
time << repeats the last time read

The debug says the end of file is reached when time is read so it seems to be looping correctly, but somewhere the value of i its adding 1 to the true value of the items

So you're saying the problem only shows up when you try to read the SECOND file. The original file ("song.dat") actually has four songs in the file and when you display it (without reading in a second file), it says you have 4 songs, and there are no stray characters in the display at all?

You should change your Display function to display the data more cleanly. I think any bugs will be more clear there. Right now you can't distinguish displaying an empty string with displaying nothing, everything is jumbled together in one line with no spacing, and you don't display the NUMBER of songs read in. It's hard to debug with that Display function.

The debug says the end of file is reached when time is read so it seems to be looping correctly, but somewhere the value of i its adding 1 to the true value of the items

So the other debug statements don't get displayed (i.e. ""End of file reached after reading genre")?

If they do, you have a problem. If they don't, you're probably OK, at least as far as the eof () loop goes.

But again, make a better Display loop that shows the info better (it'll be much easier to debug that way and it'll look much nicer), and make sure everything is PERFECT when you read in song.dat before trying to read the second file. I fear you are mixing two errors. Fix the first one first.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.