Thread: methods for class List

  1. #1
    Registered User CASHOUT's Avatar
    Join Date
    Jul 2011
    Location
    Florida
    Posts
    88

    methods for class List

    Creating the methods for class List

    main.cpp
    Code:
    #include    "List.h"
    
    
    int main( )
    {
        List la;                    // create list la
    
        la.push_front( "mom" );
        la.push_back( "please" );
        la.push_back( "send" );
        la.push_back( "money" );
        la.push_front( "hi" );
    
        cout << "\nla contains:\n" << la << '\n';
    
        List lb( la );              // copy list la to lb
    
        cout << "lb contains:\n" << lb << '\n';
    
        lb.pop_front( );
        lb.pop_front( );
        lb.push_front( "mother" );
        lb.push_front( "dear" );
        lb.push_back( "Bubba" );
    
        cout << "lb contains:\n" << lb << '\n';
    
        List lc;                    // create list lc
        lc.push_back( "money" );
        lc.push_front( "send" );
    
        cout << "\nlc contains:\n" << lc << '\n';
    
        List ld;                    // create list ld
        cout << "\nld contains nothing:\n" << ld << '\n';
    
        ld.push_front( "hi" );
        cout << "ld contains:\n" << ld << '\n';
    
        ld.pop_front( );
        cout << "ld contains nothing:\n" << ld << '\n';
    
        ld.push_back( "hello" );
        ld.push_back( "Bubba" );
        cout << "ld contains:\n" << ld << '\n';
    
        ld.pop_front( );
        cout << "ld contains:\n" << ld << '\n';
    
        ld.pop_front( );
        cout << "ld contains nothing:\n" << ld << '\n';
    
        List le( ld );
        cout << "le contains nothing:\n" << le << '\n';
    
        le.push_back( "last" );
        cout << "le contains:\n" << le << '\n';
       return 0;
    }

    List.h
    Code:
    #include    <iostream>
    #include    <iomanip>
    #include    <string>
    using namespace std;
    
    
    class Node
    {
      public:
                                        // constructor
        Node( const string &, Node *, Node * );
    
        const string &get_word( ) const;// get a const reference to word
        Node   *get_next( ) const;      // get a Node * (value of next)
        Node   *get_prev( ) const;      // get a Node * (value of prev)
        Node   *set_next( Node * );     // set next to a new value
        Node   *set_prev( Node * );     // set prev to a new value
    
      private:
        string   word;
        Node    *next;
        Node    *prev;
    };
    
    
    class List
    {
      public:
        List( );                        // constructor
        List( const List & );           // copy constructor
        ~List( );                       // destructor
                                        // push a node to the back of list
        void push_back( const string & );
                                        // push a node to the front of list
        void push_front( const string & );
                                        // pop  a node from the back  of list
        void pop_back( );
                                        // pop  a node from the front of list
        void pop_front( );
                                        // member function for the optional part
        List &operator =( const List & );
                                        // output a list object
        friend ostream &operator <<( ostream &, const List & );
    
        Node *begin( ) const;           // pointer to beginning of the list
        Node *end( ) const;             // pointer to end       of the list
    
        class Iterator
        {
          public:
            Iterator( Node * );
                                        // same as word( )
            const string &operator *( ) const;
            void operator ++( );        // same as next( )
            bool operator !=( Node * ) const;
    
          private:
            Node *current;
        };
    
      private:
    
        Node    *head;
        Node    *tail;
    
        void copy_list( const List &  );// copy a linked list
        void delete_list( );            // delete a linked list
    };


    methods.cpp
    Code:
    #include    "List.h"
    
    
    /**************************************methods for Node**************************************/
    							// constructor: init. a Node
    Node::Node( const string &s, Node * n, Node * p )
    {
        word = s;               // init. word with a copy of s
        next = n;               // next points to n
    	prev = p;				// prev points to p
    }
    
                                // return a const ref to word
    const string &Node::get_word( ) const
    {
        return (*this).word;
    }
    
                                // return a pointer to next node
    Node *Node::get_next( ) const
    {
        return (*this).next;
    }
    
    
    Node *Node::get_prev( ) const 
    {
    	return (*this).prev;
    }
    
                                // sets next to pointer n and return next
    Node *Node::set_next( Node * n )
    {
        next = n;               // next now points to n
        return (*this).next;
    }
    
    							// sets prev to pointer p and return prev
    Node *Node::set_prev( Node * p )
    {
    	prev = p;				// prev now points to p
    	return (*this).prev;   
    }
    
    
    
    /**************************************methods for List**************************************/ 
    
    List::List( )               // constructor: init. head and tail
    {
        cout << "List::List( )\n";
    
        head = tail = 0;
    }
    
    
    List::List( const List &rhs )// copy constructor
    {
        copy_list( rhs );
    }
    
    
    List::~List( )              // destructor: delete the list
    {
        cout << "List::~List( )\n";
        delete_list( );
    }
    
    
    void List::copy_list( const List &rhs )
    {
        head = tail = 0;
                                // copy rhs' list into this
        for( Node *p = rhs.begin(); p != end(); p = p->get_next( ) )
        {
            push_back( p->get_word( ) );
        }
    }
    
    
    void List::push_back( const string &s )
    {
                                // p points to a new node
        Node *p = new Node( s, 0, tail );
    
        if( tail == 0 )         // tail not pointing to a node yet?
        {
            head = tail = p;    // head & tail point to new node in the list
        }
        else
        {                       // tail->next points to new node
            tail->set_next( p );
            tail = p;           // tail points to last node in the list
        }
    }
    
    
    void List::pop_back( )
    {
        if( tail )              // tail points to a node?
        {
            Node *tmp = tail;
            tail      = tail->get_prev( );
    
            delete tmp;         // delete node to be removed
    
            if( tail == 0 )     // no more elements in the list?
            {
                head = 0;
            }
            else
            {
                tail->set_next( 0 );
            }
        }
    }
    
    
    void List::delete_list( )   // delete a linked list
    {
        // . . .
    	 cout << "List::~List( )\n";
    
        for( Node *p = head; p; )
        {
            Node *tmp = p;      // remember current pointer
            p = p->get_next( ); // advance p to the next Node
            delete tmp;         // deallocate tmp
            cout << "deallocated\t" << tmp << "\tnext is\t" << p << '\n';
        }
    }
    
    
    void List::push_front( const string &s )
    {
    	                       // p points to a new node
        Node *p = new Node( s, 0, head );
    
        if( head == 0 )         // head not pointing to a node?
        {
            tail = head = p;   
        }
        else
        {                       // tail->next points to new node
            tail->set_next( p );
            tail = p;           // tail points to last node in the list
        }
    
    }
    
    
    void List::pop_front( )
    {
    	if ( head )
    	{
    
    		Node *tmp = head;
            head      = head->get_next( );
    
            delete tmp;         // delete node to be removed
    
            if( tail == 0 )     // no more elements in the list?
            {
                head = 0;
            }
            else
            {
                tail->set_next( 0 );
            }
    
    	}
    }
    
    
                                // method for the optional
    //List &List::operator =( const List &rhs )
    //{
    //	head = tail = 0;
    //    // . . .
    //	if( this != &rhs )        // left and right objects are NOT the same?
    //    {                       
    //        delete [ ] this;   // delete stack that belongs to left side object
    //
    //        head = rhs.head;
    //        tail = rhs.tail;
    //			                    // now copy right side object to left side object
    //			for( Node *p = rhs.head; p; p = p->get_next( ) )
    //			{
    //				push_back( p->get_word( ) );
    //			}
    //    }
    //
    //    return *this;           // return a reference to left-hand side object
    //}
    
    
    ostream &operator <<( ostream &out, const List &list )
    {
        for( Node *p = list.head; p != 0; p = p->get_next( ) )
        {
            cout << p << '\t' << setw( 8 ) << p->get_word( )
                 << '\t' << "next:" << '\t' << p->get_next( ) << '\n';
        }
    
        return out;
    }
    
    
    Node *List::begin( ) const  // beginning of a linked list
    {
        return head;
    }
    
    
    Node *List::end( ) const    // end of a linked list
    {
        return 0;
    }
    
    
    
    
    /**************************************methods for Iterator**************************************/ 
                                // constructor: init. an Iterator
    List::Iterator::Iterator( Node * p )
    {
        current = p;            // current points to p
    }
    
                                // get a const ref to word
    const string &List::Iterator::operator *( ) const
    {
        return current->get_word( );
    }
    
                                // get a const ref to word
    void List::Iterator::operator ++( )
    {
        if( current )
        {
            current = current->get_next( );
        }
    }
    
                                // current != p
    bool List::Iterator::operator !=( Node * p ) const
    {
        return current != p;
    }



    Output should look like this:

    List::List( )

    la contains:
    00000000 hi 00348750
    00348990 mom 003487E0
    00348750 please 00348870
    003487E0 send 00348900
    00348870 money 00000000

    lb contains:
    00000000 hi 00348CA8
    00348A98 mom 00348D00
    00348CA8 please 00348D90
    00348D00 send 00348E20
    00348D90 money 00000000

    lb contains:
    00000000 dear 00348A98
    00348CA8 mother 00348D00
    00348A98 please 00348D90
    00348D00 send 00348E20
    00348D90 money 00348EE8
    00348E20 Bubba 00000000

    List::List( )

    lc contains:
    00000000 send 00348F78
    00349008 money 00000000

    List::List( )

    ld contains nothing:

    ld contains:
    00000000 hi 00000000

    ld contains nothing:

    ld contains:
    00000000 hello 00349128
    00349098 Bubba 00000000

    ld contains:
    00000000 Bubba 00000000

    ld contains nothing:

    le contains nothing:

    le contains:
    00000000 last 00000000

    List::~List( )
    deallocating 00349098 with last next is 00000000
    List::~List( )
    deallocating 00349128 with last next is 00000000
    List::~List( )
    deallocating 00349008 with send next is 00348F78
    deallocating 00348F78 with money next is 00000000
    List::~List( )
    deallocating 00348CA8 with dear next is 00348A98
    deallocating 00348A98 with mother next is 00348D00
    deallocating 00348D00 with please next is 00348D90
    deallocating 00348D90 with send next is 00348E20
    deallocating 00348E20 with money next is 00348EE8
    deallocating 00348EE8 with Bubba next is 00000000
    List::~List( )
    deallocating 00348750 with last next is 00000000

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    I do not understand. Is there a question somewhere in this long post?
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    Registered User CASHOUT's Avatar
    Join Date
    Jul 2011
    Location
    Florida
    Posts
    88
    Quote Originally Posted by vart View Post
    I do not understand. Is there a question somewhere in this long post?
    Okay so my first question is why push_front properly pushing "mom" to the front of the list but not pushing "hi" to the frint of the list? instead "hi" is being pushed to the back of the list.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Why is push_front adding the new node to tail?
    >tail->set_next( p );
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Registered User CASHOUT's Avatar
    Join Date
    Jul 2011
    Location
    Florida
    Posts
    88
    Quote Originally Posted by Elysia View Post
    Why is push_front adding the new node to tail?
    >tail->set_next( p );
    Thank you for pointing that out.

    Code:
    void List::push_front( const string &s )
    {
    	               // p points to a new node
        Node *p = new Node( s, 0, head );
     
        if( head == 0 )         // head not pointing to a node?
        {
            tail = head = p;  
        }
        else
        {                       // head->next points to new node
    		head->set_next( p );
        }
    
    }
    I changed it so push_front is adding a new node to head. (unfavorable outcome)

    After playing with the code for a bit, I'm still confused as to why the output changed so much.

    "hi" is still not at the top of the list, and the rest of the output disappeared.

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I could probably tell you why, but I want you to figure this out. So grab a debugger, and get started stepping through the code. Remember to check variables to see if your list is intact.
    If you don't have a debugger already, Visual Studio comes with one that is extremely simple to use.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User CASHOUT's Avatar
    Join Date
    Jul 2011
    Location
    Florida
    Posts
    88
    Quote Originally Posted by Elysia View Post
    I could probably tell you why, but I want you to figure this out. So grab a debugger, and get started stepping through the code. Remember to check variables to see if your list is intact.
    If you don't have a debugger already, Visual Studio comes with one that is extremely simple to use.
    I'll keep working with the debugger.
    Should my main focus be on debugging push_front()?

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    First step is to figure out the source of the problem, where it occurs. For example, you can quickly step over all your calls to the list and after each, check if the list is okay.
    When you find that it is not okay anymore, you've found where the problem occurs. From there, you should check to see if you can puzzle out why it happened. If you can't, it means you need to restart and go back in time to see if you can spot anything wrong.
    Limiting the scope comes after you've figured out the scope of the problem, ie have more details on why and how it occurs. If it's a call to push_front that messes up the list, then it's a good assumption that it may be the culprit, so you can check if you're right. If you are, then you've found your bug. If not, you need to consider other functions, as well.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    There is nothing to stop you using the debugger as part of your normal edit-compile-test cycle.

    Which would consist of
    - write a function
    - put one (or more) calls to the function in main()
    - compile (keep editing until it compiles)
    - load the program in the debugger
    - single step through your new function, checking variables, data, control flow are as you expect.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    The list class has a design flaw:

    Code:
        Node *begin( ) const;           // pointer to beginning of the list
        Node *end( ) const;             // pointer to end       of the list
    With these public methods I now have access to the internal nodes, and the interface of the nodes which is intended for the list class, not me. I could change the the list outside of the List class interface. Instead, you need to be able to do:
    Code:
    Iterator List::begin() const
    {  return Iterator(head);  }
    
    Iterator List::end() const
    {  return Iterator(tail);  }
    I would fix this now.

  11. #11
    Registered User CASHOUT's Avatar
    Join Date
    Jul 2011
    Location
    Florida
    Posts
    88
    Quote Originally Posted by Elysia View Post
    First step is to figure out the source of the problem, where it occurs. For example, you can quickly step over all your calls to the list and after each, check if the list is okay.
    When you find that it is not okay anymore, you've found where the problem occurs. From there, you should check to see if you can puzzle out why it happened. If you can't, it means you need to restart and go back in time to see if you can spot anything wrong.
    Limiting the scope comes after you've figured out the scope of the problem, ie have more details on why and how it occurs. If it's a call to push_front that messes up the list, then it's a good assumption that it may be the culprit, so you can check if you're right. If you are, then you've found your bug. If not, you need to consider other functions, as well.


    The debugger helped open my eyes to the problem, and in the process became my new best friend.
    Thank you.

    I have more questions but I'm going to ask my new best friend for the answers first.

  12. #12
    Registered User CASHOUT's Avatar
    Join Date
    Jul 2011
    Location
    Florida
    Posts
    88

    operator =

    After applying this optional part to the end of function main()

    Code:
     cout << "\n\nOPTIONAL PART\n";
    
    	ld = la;
        cout << "\nla contains:\n" << la << '\n';
        cout << "\nld contains:\n" << ld << '\n';
    
    	la = ld = le;
        cout << "\nle contains:\n" << le << '\n';
        cout << "\nld contains:\n" << ld << '\n';
        cout << "\nla contains:\n" << la << '\n';
    
    	le = le;
        cout << "\nle contains:\n" << le << '\n';
    
        cout << "END OPTIONAL PART\n\n";
    I came up with this method for operator =
    Code:
                                // method for the optional
    List &List::operator =( const List &rhs )
    {   	
    	if( this != &rhs )        // left and right objects are NOT the same?
        {                       
          	head = rhs.head;
            tail = rhs.tail;
    	}
    
        return *this;           // return a reference to left-hand side object
    }
    The program ran decent before the operator= implementation.

    Now, ld.pop_front("hi") pops hi, cout prints ld to standard output, then the compiler gives a heap corruption message.


    The output with the optional part is supposed to look like this:

    List::List( )

    la contains:
    00000000 hi 00348750
    00348990 mom 003487E0
    00348750 please 00348870
    003487E0 send 00348900
    00348870 money 00000000

    lb contains:
    00000000 hi 00348CA8
    00348A98 mom 00348D00
    00348CA8 please 00348D90
    00348D00 send 00348E20
    00348D90 money 00000000

    lb contains:
    00000000 dear 00348A98
    00348CA8 mother 00348D00
    00348A98 please 00348D90
    00348D00 send 00348E20
    00348D90 money 00348EE8
    00348E20 Bubba 00000000

    List::List( )

    lc contains:
    00000000 send 00348F78
    00349008 money 00000000

    List::List( )

    ld contains nothing:

    ld contains:
    00000000 hi 00000000

    ld contains nothing:

    ld contains:
    00000000 hello 00349128
    00349098 Bubba 00000000

    ld contains:
    00000000 Bubba 00000000

    ld contains nothing:

    le contains nothing:

    le contains:
    00000000 last 00000000



    OPTIONAL PART

    la contains:
    00000000 hi 00348750
    00348990 mom 003487E0
    00348750 please 00348870
    003487E0 send 00348900
    00348870 money 00000000


    ld contains:
    00000000 hi 00349180
    00349128 mom 00349210
    00349180 please 003492A0
    00349210 send 00349330
    003492A0 money 00000000

    deallocating 00349128 with hi next is 00349180
    deallocating 00349180 with mom next is 00349210
    deallocating 00349210 with please next is 003492A0
    deallocating 003492A0 with send next is 00349330
    deallocating 00349330 with money next is 00000000
    deallocating 00348990 with hi next is 00348750
    deallocating 00348750 with mom next is 003487E0
    deallocating 003487E0 with please next is 00348870
    deallocating 00348870 with send next is 00348900
    deallocating 00348900 with money next is 00000000

    le contains:
    00000000 last 00000000


    ld contains:
    00000000 last 00000000


    la contains:
    00000000 last 00000000


    le contains:
    00000000 last 00000000

    END OPTIONAL PART

    List::~List( )
    deallocating 00349098 with last next is 00000000
    List::~List( )
    deallocating 00349128 with last next is 00000000
    List::~List( )
    deallocating 00349008 with send next is 00348F78
    deallocating 00348F78 with money next is 00000000
    List::~List( )
    deallocating 00348CA8 with dear next is 00348A98
    deallocating 00348A98 with mother next is 00348D00
    deallocating 00348D00 with please next is 00348D90
    deallocating 00348D90 with send next is 00348E20
    deallocating 00348E20 with money next is 00348EE8
    deallocating 00348EE8 with Bubba next is 00000000
    List::~List( )
    deallocating 00348750 with last next is 00000000


    also the deallocation output is missing the variable that contains the word being deallocated. Not sure what variable I should be using to display the value being deallocated.

    I thought dereferencing the pointer would display the value to cout rather than the location but that didn't work.

  13. #13
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    All your lists are sharing pointers.
    When la goes out of scope, it destroys its list.
    When ld goes out scope, it destroys its list, which it shares with la, which it already destroyed, etc.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Class methods
    By CASHOUT in forum C++ Programming
    Replies: 5
    Last Post: 06-13-2013, 09:20 PM
  2. Class communication methods
    By cboard_member in forum Game Programming
    Replies: 2
    Last Post: 02-23-2006, 12:25 PM
  3. Defining class methods
    By sand_man in forum C++ Programming
    Replies: 2
    Last Post: 11-01-2005, 06:09 AM
  4. problem w/ class methods
    By earth_angel in forum C++ Programming
    Replies: 5
    Last Post: 08-30-2005, 06:41 AM
  5. Exporting Class methods to a DLL
    By EvBladeRunnervE in forum Windows Programming
    Replies: 2
    Last Post: 12-09-2003, 07:29 PM