1. Not finding help here? Sign up for a free 30min tutor trial with Chegg Tutors
    Dismiss Notice
Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

C++ object oriented, classes/methods

  1. Dec 11, 2013 #1
    1. The problem statement, all variables and given/known data
    The problem statement is very long, but in a pinch, I'm supposed to take a text file and use 2 different classes, Song class, and Song_Library class to sort, print, etc..

    I'm running into the problem(among others) of my output being really really dumb. And I think it's in my read_songs() function. But I'll post the entire code for you to see, because, what do I know, I'm just a math major! :)

    The program is also supposed to sort the list by either title or length, which it's not, but I'll worry about that after I get it to read correctly. And it is supposed to shuffle the list, which you'll notice I have an empty method for that, it's to come later.

    Generally I'd be emailing my GTA, but he seems to have gone to bed since it not due until tomorrow at midnight, but I need to get it done sooner than that. I've got other stuff to worry about tomorrow. :)


    2. Relevant equations



    3. The attempt at a solution
    Code (Text):
    #include <cstdlib>
    #include <fstream>
    #include <iomanip>
    #include <iostream>
    using namespace std;

    class Song
    {
    public:
       Song();
       void set(string t, string g, string a, int y, int l);
       void get(string& t, string& g, string& a, int& y, int& l);
       void print();
       string get_title();
       int get_length();

    private:
       string Title;
       string Genre;
       int Year;
       string Artist;
       int Length;
    };

    //-----------------------------------------------------------

    class Song_Library
    {
    public:
       Song_Library();
       Song_Library(string filename);
       bool is_empty();
       void sort_title();
       void sort_length();
       void shuffle();
       void print();
    private:
       static const int SIZE = 20;
       Song list[SIZE];
       int count;
    };
    //------------------------------------------------------------
    //Methods for Song class
    //------------------------------------------------------------

    Song::Song()
    {

       Title = "ttt";
       Genre = "ggg";
       Artist = "aaa";
       Length = 0;
       Year = 2013;

    }


    void Song::set(string t, string g, string a, int y, int l)
    {

       Title = t;
       Genre = g;
       Artist = a;
       Length = l;
       Year = y;

    }

    void Song::get(string &t, string &g, string &a, int &y, int &l)
    {

       t = Title;
       g = Genre;
       a = Artist;
       l = Length;
       y = Year;

    }

    string Song::get_title()
    {
     return Title;
    }

    int Song::get_length()
    {
     return Length;
    }

    void Song::print()
    {
       cout << setw(30) << Title
            << setw(10) << Genre
            << setw(30) << Artist
            << setw(10) << Length
            << setw(10) << Year << endl;
    }

    //Methods for Song_Library class
    //---------------------------------------------------
    Song_Library::Song_Library()
    {
     count = 0;
    }

    Song_Library::Song_Library(const string filename)
    {
     fstream infile;
     infile.open("songs.txt");

       string title;
       string genre;
       string artist;
       string year;
       string seconds;
       string blank;
       count = 0;
       while (count < SIZE && !infile.eof())
       {
       //   getline(infile, title);
          Song get_title();
          getline(infile, genre);
          getline(infile, artist);
          getline(infile, year);
       //   getline(infile, seconds);
          Song get_length();
          getline(infile, blank);
          int iseconds = atoi(seconds.c_str());
          int iyear = atoi(year.c_str());
          list[count].set(title, genre, artist, iyear, iseconds);
          count++;
       }

    }
    bool Song_Library::is_empty()
    {
      if((count = 0))
        return true;
      else
        return false;
    }

    void Song_Library::sort_title()
    {
     for (int index = 0; index < SIZE; index++)
       {
          // Find location of smallest value in unsorted part
          int location = index;
          for (int pos = index; pos < SIZE; pos++)
             if (list[pos].get_title() < list[location].get_title())
                location = pos;

          // Swap value to end of sorted part
          Song temp = list[index];
          list[index] = list[location];
          list[location] = temp;
       }


    }

    void Song_Library::sort_length()
    {
     for (int index = 0; index < SIZE; index++)
       {
          int location = index;
          for (int pos = index; pos < SIZE; pos++)
              if (list[pos].get_length() < list[location].get_length())
                 location = pos;

          Song temp = list[index];
          list[index] = list[location];
          list[location] = temp;
       }
    }

    void Song_Library::shuffle()
    {


    }

    void Song_Library::print()
    {
       cout << setw(30) << "Title"
            << setw(10) << "Genre"
            << setw(30) << "Artist"
            << setw(10) << "Seconds"
            << setw(10) << "Year" << endl;
       for (int index = 0; index < SIZE; index++)
          list[index].print();
       cout << endl;

    }
    //---------------------------------------------------
    void read_songs(Song list[], int size, int &count)
    {
       string title;
       string genre;
       string artist;
       string year;
       string seconds;
       string blank;
       count = 0;
       fstream infile;
       infile.open("songs.txt");
       while (count < size && !infile.eof())
       {
       //   getline(infile, title);
          Song get_title();
          getline(infile, genre);
          getline(infile, artist);
          getline(infile, year);
       //   getline(infile, seconds);
          Song get_length();
          getline(infile, blank);
          int iseconds = atoi(seconds.c_str());
          int iyear = atoi(year.c_str());
          list[count].set(title, genre, artist, iyear, iseconds);
          count++;
       }
    }


    //---------------------------------------------------------
    void print_menu(){
        cout << "Please select one of the following options:\n";
        cout << "0: for quiting\n";
        cout << "1: for printing\n";
        cout << "2: for sorting title\n";
        cout << "3: for sorting length\n";
        cout << "4: for shuffling\n";
        cout << "Please type 0 or 1 or 2 or 3 or 4\n";
    }
    //----------------------------------------------------------
    int get_option(){
        char option;
        string s;
        cin.get(option);
        getline(cin,s);
        while (!( option >= '0' && option <= '4')){
            cout << "Wrong option value\n";
            print_menu();
            cin.get(option);
            getline(cin,s);
        }
        return option - '0';
    }
    //-----------------------------------------------------------
    int main(int argc, char** argv)
    {

        // initialize library from a file
        Song_Library lib("songs.txt");

        // menu loop
        int option = -1;
        while ( option != 0 ){
            print_menu();
            option = get_option();

            // handle the user commands
            switch (option){
                case 0:{
                    cout << "Have a good day. Program is terminating\n";
                    break;
                }
                case 1:{
                    if ( lib.is_empty()) {
                        cout << "Nothing to print for an empty library\n";
                    } else {
                        lib.print();
                    }
                    break;
                }
                case 2: {
                    if ( lib.is_empty()) {
                        cout << "No title to sort for an empty library\n";
                    } else {
                        lib.sort_title();
                        lib.print();
                    }
                    break;
                }
                case 3: {
                     if ( lib.is_empty()) {
                        cout << "No title to sort for an empty library\n";
                    } else {
                        lib.sort_length();
                        lib.print();
                    }
                    break;
                }
                case 4: {
                    if ( lib.is_empty()) {
                        cout << "No title to shuffle for an empty library\n";
                    } else {
                        lib.shuffle();
                        lib.print();
                    }
                    break;
                }
            }
        }
        return 0;
    }
    Here is the text file being read(This was given to us, don't judge the selection!)

    Code (Text):
    Roar
    Pop
    Katy Perry
    2013
    270

    Royals
    Pop
    Lorde
    2013
    201

    Wrecking Ball
    Pop
    Miley Cyrus
    2013
    222

    Rap God
    Hip Hop
    Eminem
    2013
    367

    Wake Me Up!
    Pop
    Avicii
    2013
    273

    Counting Stars
    Rock
    OneRepublic
    2013
    257

    Hold On, We're Going Home
    Hip Hop
    Drake Featuring Majid Jordan
    2013
    227

    The Fox
    EDM
    Ylvis
    2013
    213
    Applause

    Pop
    Lady Gaga
    2013
    212
    1. The problem statement, all variables and given/known data



    2. Relevant equations



    3. The attempt at a solution
     
  2. jcsd
  3. Dec 12, 2013 #2

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Here's your problem:
    Code (Text):
       //   getline(infile, title);
          Song get_title();
          getline(infile, genre);
          getline(infile, artist);
          getline(infile, year);
       //   getline(infile, seconds);
          Song get_length();
     
    *You* commented out two critical lines of code and replaced them with nonsense. Your Song::get_title() and Song::get_length() don't get a value for the title and length from the input file. They return the current value of the song's title and length data members.

    Learn to use a debugger. You would have found this error immediately while walking the debugger through your code.
     
  4. Dec 12, 2013 #3

    Mark44

    Staff: Mentor

    You didn't provide much info to go on to help you debug this, so I'll just list a couple of things I spotted. In main, you call your Song_Library constructor, passing the name of the text file. In the constructor you don't use the passed filename - you use a hard-coded string when you call infile.open. Since you say you're getting output, I have to assume that your code is able to find the text file.

    The Song_Library constructor doesn't set iseconds correctly. Here's the relevant code:
    Code (Text):
       //   getline(infile, seconds);
          Song get_length();
          getline(infile, blank);
          int iseconds = atoi(seconds.c_str());
    You have the first line commented out, so seconds is set with some garbage value. A few lines later you convert that garbage value to an int and store it in iseconds. That's guaranteed to give you a bad value for the song's time.

    What debugger do you have available? If you know how to use it, that would be very helpful, as you could set a breakpoint at a location where you're not sure you're getting the right value. If you don't have a debugger available (probably not likely) or do have one around but don't know how to use it, you could always fall back to the timeworn debugging technique of liberally adding simple output statements your code that display the value of some variable. If you're getting the expected values, you can remove or comment out those output statements.
     
  5. Dec 12, 2013 #4
    We have not been made aware of any debuggers. We are just using nano on an Ubuntu server we are accessing via a secure shell.

    I uncommented the getline... pieces and took out the other ones, and it is reading and sorting correctly now. Thanks!

    Now I'm having trouble with the shuffle method. Its compiling but I'm getting a segmentation fault. I think, its because of the way I've tried to sort it has no way of guaranteeing that each position I'm the array has a unique assignment and that each position is used. This is because I had very little idea of how to randomize the sort. So my code for this method is not much more than a shot in the dark. So a nudge in the right direction would be great.

    Here is my code for that method right now:

    Code (Text):
    void Song_Library::shuffle()
    {
     int location = random();
     for(int index = 0; index < SIZE; index++)
      {
       Song temp = list[index];
       list[index] = list[location];
       list[location] = temp;
       }
    }

    And again, there is not much reasoning behind this.
     
    Last edited: Dec 12, 2013
  6. Dec 12, 2013 #5

    Mark44

    Staff: Mentor

    Where are you getting your random function? There's a rand() function in cstdlib, but I don't see a random function. location needs to be set to a valid index in your list of Song instances.

    Also, I believe you are using SIZE as the maximum possible index in your list. You should be using the actual size (I think you call it count) in your loop, rather than the maximum size.
     
  7. Dec 12, 2013 #6
    As I said, it was a misguided effort. The random() function, was what I thought was like a "default" operator.

    Ok, so do I need to change it to " int location = index" and then move it down into my for loop.

    I was using my other sort methods as examples for this one. Following that thought process, would it make since to have essentially the same code as the other sort methods and but change the part where it determines what needs to be swapped?

    (and maybe I should have started with this)
    For example:

    Code (Text):
    void Song_Library::sort_length()
    {                
     for (int index = 0; index < SIZE; index++)
       {        
          int location = index;            
          [B][I]for (int pos = index; pos < SIZE; pos++)
              if (list[pos].get_length() < list[location].get_length())
                 location = pos;[/I][/B]

          Song temp = list[index];
          list[index] = list[location];
          list[location] = temp;  
       }
    }
    In this sort method, the part in bold is the code that is determining what to sort(right?).

    So would my shuffle method resemble this, but with different code in bold?


    Yeah, I was actually thinking I needed to change that because every time I run the program it prints 20 lines everytime regardless of how much data is in the file.

    I was waiting to fix that because, I was thinking I needed to change every instance of "SIZE" to "count"? Is that right?
     
  8. Dec 12, 2013 #7
    Ok, I've got my shuffle working, (a classmate pointed me in the direction of some sample code from our lecture notes)

    Here is the shuffle method I used:

    Code (Text):
    void Song_Library::shuffle()
    {
     int Swap;
     Song temp;
     srand(time(0));
     for(int index = 0; index < SIZE; index++)
        {
         for(int pos = index; pos < SIZE; pos++)
            {
             Swap = rand() % SIZE;
             temp = list[Swap];
             list[Swap] = list[index];
             list[index] = temp;
            }
        }
    }
     
    It works, but that doesn't necessarily mean it's right, and I'm not sure what everything here is doing.

    First, is the "srand(time(0))" - I don't know what this is doing.

    Next, the example in the notes wasn't exactly this, but it was very similiar, however, they had a the for loop inside of a for loop like I have, but in this instance, I don't feel both are necessary.
    I commented out one of the loops, and it still works, but like I said, that doesn't mean it's right. Can you verify this?
     
  9. Dec 12, 2013 #8

    Mark44

    Staff: Mentor

    You could use the rand() function. It's not an operator.
    I'll have to think about that.
    Sounds like a good idea.
    No, but you need to understand what SIZE and count represent. SIZE is the maximum number of elements in your list of Song objects. count is the actual number of elements in this list. If the input text file has only 14 songs in it, count should reflect that. All or most of your functions should be using count, not SIZE. Otherwise, unless your textfile contains exactly SIZE (20) songs, the loops will be processing some garbage data.

    Writing code where you don't understand what the code is doing is not a good idea. It would be a good idea to hand-simulate what your code is doing with a small set of data, say four songs. Assume that your list starts out sorted in some way (by artist, by song title, whatever). Working with a piece of paper and a pen or pencil, see if you can figure out what your list might look like after each loop iteration.
    srand(...) seeds the random number generator. Generally you need to to this only once.
    It sounds like you might be talking about a sort function, not a shuffle function.
     
  10. Dec 12, 2013 #9
    The only thing I didn't understand was the srand(...) part. From there I can follow what the loops are doing, which is why I questioned the need for a nested for loop.

    The function I was looking at was actually labeled as a shuffle() method.

    It was dealing with a deck of cards, and the first for loop was telling it to run 7 times, presumably for hands?


    What were you saying No to?
    This part of the code was what was confusing me, because what you said makes sense and it was what I expected but when I changed the instances of SIZE to count that needed to be changed, it wouldn't print anything, so after I got everything figured out, I added cout statements to tell me what value of count was at each method, I figured out that it was passing as 0 after the is_empty() method. Then I saw that I had, if((count = 0)) rather than if(count == 0), so when ithe main function called is_empty() it would reset count to 0. So all is good now. And the program is working as intended! So, thanks!
     
  11. Dec 12, 2013 #10

    Mark44

    Staff: Mentor

    The "No" was in response to your question, which was quoted just above my reply.
    What I meant was that you shouldn't do a blanket replacement of SIZE to count everywhere, only where it was necessary to make that change.
    Excellent! I personally get a lot of satisfaction when I have written some code and it works just right!
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook

Have something to add?
Draft saved Draft deleted



Similar Discussions: C++ object oriented, classes/methods
  1. Classes and objects (Replies: 0)

  2. Java object method (Replies: 23)

Loading...