Thread: Help loading a vector with input from input stream

  1. #1
    Registered User
    Join Date
    Sep 2006
    Posts
    55

    Help loading a vector with input from input stream

    I am trying to load the vector of strings "Names" which is a private data member for the class "BagOfNames" from the istream using cin. However, I am having trouble with the syntax to do so in the "void input_names ()" function. Can someone please help? Thank you.


    Code:
    #include <fstream>
    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std ;
    
    class BagOfNames
    {
      public:
       void input_names(istream& name_p);
       // assumes that an ifstream object is already opened (or cin) 
       // is used as an argument for inStream_p
    
       void output_names(ostream& outStream_p);
       // assumes that an ofstream object is already opened (or cout) 
       // is used as an argument for outStream_p
    
       void erase_name(string aName_p);
       void add_name(string aName_p);
       string get_random_name();
       string get_longest_name();
       void delete_duplicates();
       vector <string> get_duplicates();
    
    
      private:
       vector <string> Names ;
    
    }; 
    
    int main ()
    {
      
      BagOfNames Students ;
      
      fstream Name_Stream ;
      string user_response ;
      
      cout << "Would you like to enter information from the keyboard?" 
           << "(Type 'yes' or 'no'): " << endl ;
      cin >> user_response ;
      
      if (user_response == "yes" )
       {
        cout << "Enter Names, one per line and use 'Ctrl Z' to end Input:" ;
        Students . input_names (cin) ;        
       } 
      else
       {
        Name_Stream . open ("E:\\CSCI 135\\Files\\Names.txt") ;
        Students . input_names (Name_Stream) ;
       } 
        
    system ("Pause") ;
    return 0 ;
    }
    
    void BagOfNames :: input_names(istream& name_p) 
    {
     Names . push_back (cin) ;
    }

  2. #2
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >void BagOfNames :: input_names(istream& name_p)
    >{
    > Names . push_back (cin) ;
    >}
    I don't believe you can do it in one statement. First do the read, then the push_back.
    Code:
    void BagOfNames::input_names(istream& name_p) 
    {
       string temp;
       name_p >> temp;
       Names.push_back (temp) ;
    }
    If the name can contain whitespace, then you'd need to use getline instead:
    Code:
    void BagOfNames::input_names(istream& name_p) 
    {
       string temp;
       getline(name_p, temp);
       Names.push_back (temp) ;
    }

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    You can do it in one line as long as the user terminates input with Ctrl-Z. You have to #include <algorithm> and <iterator> for copy, istream_iterator, and back_inserter.
    Code:
    std::copy(std::istream_iterator<std::string>(name_p), std::istream_iterator<std::string>(),
        back_inserter(Names));

  4. #4
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Quote Originally Posted by Daved
    You can do it in one line as long as the user terminates input with Ctrl-Z. You have to #include <algorithm> and <iterator> for copy, istream_iterator, and back_inserter.
    That's nice. With the input prompt Bnchs is using, it would work well in this case. The only gotcha would be if a name contained whitespace.

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> The only gotcha would be if a name contained whitespace.
    That's true. The copy method only works if the names don't contain internal whitespace, which is probably not the case. You might be able to spruce up my code to get it to handle that situation, but I would just use getline in a loop. Make sure to use getline as the control for the loop (e.g. while (getline(name_p, temp))) so it will break on end-of-file or error.

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    55
    I am sure that all of your suggestions work(and I am very grateful for your help), however, we have not covered them in class ( namely getline and back_inserter) so there has to be a way to do this using only the class and vector.

    In class the professor put :

    Code:
    if (user_response == "yes" )
       {
        cout << "Enter Names, one per line and use 'Ctrl Z' to end Input:" ;
        Students . input_names (cin) ;        
       }
    When that block was executed, he was able to input multiple names in the cin stream and end it with ctrl z . but I did not catch how he implemented it within the input_names () function. And I know that he did not use an accessor fuction to get the cin stream into the input_names () function. That is why I think the parameter placeholder is there:

    Code:
    void BagOfNames :: input_names(istream& name_p) 
    {
     Names . push_back (cin) ;
    }
    So by doing the following:
    Code:
    Students . input_names (cin) ;
    I thought that the cin stream would take the place of the parameter placeholder and when I loaded the vector it would do just that:
    Code:
    void BagOfNames :: input_names(istream& name_p) 
    {
     Names . push_back (cin) ;
    }
    Instead I got a syntax error I cannot fix even if I use the placeholder name_p instead of cin.
    Last edited by Bnchs; 11-07-2006 at 07:33 AM.

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    The point of the function taking an istream reference is that it can handle cin or an ifstream. So inside the function, you shouldn't be using cin at all, you should be using name_p.

    You cannot push an istream on to a vector, so that code won't work no matter whether you use cin or name_p anwyway. So the question is how to get all the names. Simply using swoopy's first example in a loop will work if you can't use getline. From the sound of the comments I would think getline would be more appropriate, and it is not an advanced feature, but if you can't use it you can do almost the same thing with operator>>.

    There's no way to do it in one line without more advanced features, so just make a loop reading in one name at a time and pushing them back into the vector.

  8. #8
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    As Daved said, it sounds like what you want is a loop inside input_names. I'm guessing this is similar to how the professor implemented it.
    Code:
    void BagOfNames::input_names(istream &name_p) 
    {
       string temp;
       while (name_p >> temp)
          Names.push_back (temp) ;
    }

  9. #9
    Registered User
    Join Date
    Sep 2006
    Posts
    55
    Okay, I understand what I was doing wrong and it is now working. The name_p stores the stuff from the cin stream and then have to send the stuff to some variable to load the vector. Thanks for everyone's help, especially since I have a test comming up on this soon.

  10. #10
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >The name_p stores the stuff from the cin stream
    I would have chosen a different name than name_p, because from the name, it's hard to tell it's coming from an input stream. in, input, input_s.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Cargo loading system
    By kyle rull in forum C Programming
    Replies: 1
    Last Post: 04-20-2009, 12:16 PM
  2. How to declare a global input stream
    By Chazij in forum C++ Programming
    Replies: 2
    Last Post: 11-18-2008, 04:53 PM
  3. Clearing the input stream
    By abh!shek in forum C Programming
    Replies: 10
    Last Post: 05-18-2008, 03:50 PM
  4. reterning a reference to the input stream
    By indigo0086 in forum C++ Programming
    Replies: 3
    Last Post: 06-22-2006, 10:29 AM
  5. clearing input stream
    By Sub in forum C++ Programming
    Replies: 2
    Last Post: 01-21-2002, 08:59 PM