   Question about scopes.
  Hi there, I am working on a text based adventure program. I am very new to programming and have a question about function scopes. In this program I have managed (with some help) to get a user input, remove any punctuation, convert to caps, then strip each word out and put it into a vector. (the idea is that I can then do conparisoms on the vectors to word lists to execute commands like (get box) for example.The problem I have is that I have devised (with some help) a method of doing everything I wanted, but when I placed the code into a function I can no longer get access to the vector called words (where I have stored the word list from the user input)If I list the vector words INSIDE the function they all display nicely. But when I try and list the vector words inside the main function it comes out as just a empty vector....Any ideas how I can get the entire vector contents to move back into the main function? Or isn't that neccercerry.// Text Phraser Code (temp) [12/12/2005] - Jynks//   Takes any user sentence input//   removes any punctuation//   Converts it to upper case//   splits the sentence into individual words//   puts each word into a vector array.#include <iostream>#include <string>#include <vector>#include <algorithm>#include <sstream>using namespace std;string userInput(); // function - USER INPUTvoid parseInput ( const string& input, vector <string> words, char delim = ' ' ); // function PHRASE INPUTint main (){    cout << "Please enter any sentence, you may use punctuation.\n\n";   string calledfunction1 = userInput();    cout << "The first called Function is - " << calledfunction1;    vector<string> words;    parseInput( calledfunction1, words );    cout << "\nThe vector called words inside MAIN:\n\n";    for (int i = 0; i < words.size(); ++i)   cout << words << endl;    cout << "\n\n\n\nPlease press enter to exit program.";    cin.ignore(cin.rdbuf()->in_avail() + 1);return 0;}//---------------------------------------------------------------------------------------------------------------------------// USER INPUT - START ---> User input function (Gets user input, removes all punctuation, converts user input into uppercase//---------------------------------------------------------------------------------------------------------------------------string userInput(){    string str1; // Declare String for user input    getline(cin, str1); // Get User Input    int i = str1.find_first_of("`~!@#$%^&*()-_=+|}][{';:/?.>,<\\\""); // Initalize "i" to the first occurence of punctuation in user input sting.    while (i != string::npos)    {    str1.erase(i, 1); // Erase i from the user input string.    i = str1.find_first_of("`~!@#$%^&*()-_=+|}][{';:/?.>,<\\\""); // Initalize "i" to the first occurence of punctuation in user input sting. (I is erased so it will find next)    }    transform( str1.begin(), str1.end(), str1.begin(), toupper ); // transform userinput into upper case.    return str1;}//------------------------------------------------------------------------------------------------------------------------------------// PHRASE INPUT - start --> Take string of words and split each word off the string and place in a seprate element of a vector.//------------------------------------------------------------------------------------------------------------------------------------void parseInput ( const string& input, vector <string> words, char delim ){    istringstream stream( input, delim );    while( !stream.eof() ) { // loop while there is data in the stream    string word; // we'll put each word here temporarily    // take the first word out of stream until we hit a delimeter,    // skipping whitespace    getline( stream, word, delim );    words.push_back( word ); // store the word    }    cout << "\n\n\nThe vector called words inside phraseInput function:\n\n";    for (int i = 0; i < words.size(); ++i)    cout << words << endl;    }For somthing else to look at here is some older code before I got a better function for handeling the word praser, this one will do a conpair to a word table looking for synonims for the word box.// Text Phraser Code (temp) [10/12/2005] - Jynks//   Takes any user sentence input//   removes any punctuation//   Converts it to upper case//   splits the sentence into individual words//   puts each word into a vector array.#include <iostream>#include <string>#include <vector>using namespace std;string userInput();string ParseWord( const string& userInput, int wordNumber );int main (){    cout << "Please enter any sentence, you may use punctuation.\n\n";   string calledfunction1 = userInput();    int wordNumber = 0;    string str1 = "temp";    vector<string> wordlist;// [START] Put the return value of the user input into a vector aray    do    {   str1 = ParseWord( calledfunction1, wordNumber );   wordlist.push_back(str1);   ++wordNumber;    }while (str1 != "");    wordlist.pop_back();// [END] Put the return value of the user input into a vector aray    string key = "temp";    int numItems = 0;    string box[13];    box[numItems++]= "BOX";    box[numItems++]= "CUBE";    box[numItems++]= "CARTON";    box[numItems++]= "CASE";    box[numItems++]= "CASKET";    box[numItems++]= "CHEST";    box[numItems++]= "CRATE";    box[numItems++]= "PACK";    box[numItems++]= "PACKAGE";    box[numItems++]= "RECEPTACLE";    box[numItems++]= "TRUNK";    box[numItems++]= "PORTMANTEAU";    box[numItems++]= "COFINE";    cout << "\nVector is:\n";    for (int i = 0; i < 13; ++i)    {   key = box;   for (int search = 0; search < wordlist.size(); search++)  if (key == wordlist[search])cout << "\nI have found the word in the Vector - " << key;    }// string key = "BOX";// for (int search = 0; search < wordlist.size(); search++)//    if (key == wordlist[search])//  cout << "\nI have found the word in the Vector - " << key;    cout << "\n\n\n\nPlease press enter to exit program.";    cin.ignore(cin.rdbuf()->in_avail() + 1);return 0;}// [START FUNCTION] (User input) - Gets user input string, removes punctuation, converts to Capsstring userInput(){    string str1;    getline(cin, str1);    for (int j=0; j<str1.length(); ++j)    {    str1[j]=toupper(str1[j]);    }    int i = str1.find_first_of("`~!@#$%^&*()-_=+|}][{';:/?.>,<\\\"");    while (i != string::npos)    {    str1.erase(i, 1);    i = str1.find_first_of("`~!@#$%^&*()-_=+|}][{';:/?.>,<\\\"");    }    return str1;}// [END FUNCTION] (User Input) - Gets user input string, removes punctuation, converts to Caps// [START FUNCTION] (Phrase Word) - Returns a single word from sentence string//   userInput = Sentence String from user//   wordNumber = Number of word in string to findstring ParseWord( const string& userInput, int wordNumber ){    const string WHITESPACE = " ";    int string_start = userInput.find_first_not_of( WHITESPACE );while( wordNumber > 0 ) {   wordNumber--;   string_start = userInput.find_first_of( WHITESPACE, string_start );   string_start = userInput.find_first_not_of( WHITESPACE, string_start );    }int string_end = userInput.find_first_of( WHITESPACE, string_start );if( string_start == string::npos ) {   string_start = 0;   string_end = 0;    }   return userInput.substr( string_start, string_end - string_start );}// [END FUNCTION] (Phrase Word) - Returns a single word from sentence string
  I didnt read the code, sorry im in a hurry, but im guessing you just need to pass the vector or make it global   ;  The problem is that you are passing the vector "by value". When calling the function, a copy of your vector is passed in, not the original. For example:#include <iostream>    void foo( int x )    {   x = 5;    }    main( int argc, char ** argv )    {   int y = 1;   cout << "old y is " << y << ", ";   foo( y );   std::cout << "new y is " << y << endl;    } This program will print "old y is 1, new y is 1" because y is passed "by value" -- x is a copy of y and the function sets the value of the copy to 5. Now, if you change the function to pass the parameter "by reference":void foo( int & x )    {   x = 5;    } it will print "old y is 1, new y is 5" because x is a reference to y. In this case, whatever is done to x is actually done to the variable it refers to -- y.   ;  In parseInput(...) is your problem.  Do you know about references?  I'm guessing yes, as you are using some for your strings.Anyways, you are passing a vector of strings to parseInput, correct?  But, since you are passing by value, what you pass get's it's contents copied to another vector of string in parseInput.  Since it is copied, whatever you do to it will not happen to the one in main().  Remember, if you make a copy of your report and hand in the copy to the teacher and she rips it apart, she is ripping apart the copy, yet nothing happens to the original.A simple solution is to use a reference, much like with your strings:(Note - I am using different function, but you'll know how to change your code to this...)// Assuming you already included the vector file and have done using std::vector// Assuming you have done the same for 'string'vector<string> vWords;FillUpVec(vWords);// FillUpVev is:void FillUpVec(vector<string> &AVec) { ... }This way, you are passing it by reference.  So, whatever you do with 'AVec' (or whatever you name it ;)) is done to 'vWords' (again, whatever you name it!).Good luck.  If you need help shout!  Lol.C++   ;  @JohnBolton and Anonymous Poster - that sound exactly what is happening... thanks. I have had problems with refrences before. It is now working...void parseInput ( const string& input, vector <string> words, char delim = ' ' )// new linevoid parseInput ( const string& input, vector <string> &words, char delim = ' ' );Quote:Original post by jyujinkai@JohnBolton and Anonymous Poster - that sound exactly what is happening... thanks. I have had problems with refrences before. It is now working...*** Source Snippet Removed ***We're glad we were able to help!P.S.There _is_ also a good performance with references, especially with vectors.  When you pass by values, you copy everything which means that if your struct is big then you'll get a performance hit.  Fortunately, if you know how to use references you would not only have good benefits, but good performance.Anyways, good luck!  A sentence parser sounds fun!C++   ;  Another option (*can* be slower depending on the exact circumstances and how smart your compiler is; but is *usually* more intuitive) is to let the vector be the return value. Since it is an object (not a pointer to some chunk of memory) this will be safe.The return value of a function should as a rule be chosen as the natural "product" of that function - a void function is one that perhaps changes stuff but doesn't really *create* anything here. In the given case it is perfectly logical to think of the process of input parsing as creating a vector of words, so we would do:vector<string> words = parseInput( calledfunction1 );// and the function becomesvector<string> parseInput ( const string& input, char delim = ' ') {    vector<string> words;// rest as before    return words;}By the way, congrats on what you have so far - you're using <string> and <vector>, proper tools for the job (and I spend a lot of time here trying to convince people of that :) ). Oh, and std::transform, very impressive. Where are you learning C++ from? Most "very new to programming" people don't have this kind of headstart :)But of course one can never stop learning, so here are some more hints:- The algorithm for filtering out characters is inefficient - each time a character is removed, all the other characters need to be shifted down to fill the gap, and then find_first_of() starts searching again from the beginning of the string. The second problem can be fixed by passing 'i' back as a second parameter to find_first_of() (it specifies the beginning character index for the search, and defaults to 0), but instead let me recommend to you some other STL algorithms (cousins of that 'transform') that are suited to the task:// First, we need to make a helper class that will be used by remove_if - it// provides an operator(), which allows an instance of the class to be treated// like a function. This is one way that std::toupper may be implemented - as// a global, singleton instance of a class with an operator() overload.// We could also do this with a function pointer, but this way is more flexible// and neater :)class charIsIn {  const vector<char> theList; // a set of characters that we check against.  public:  // Here's how we make an instance:  charIsIn(const char* const list):theList(list, list + strlen(list)) {}  // That's a little subtle. I'm using the two-iterator constructor of the  // vector of char - a char* counts as an iterator over chars. The "beginning"  // of the chars we want to put in to the vector is simply the input pointer,  // and the "end" is offset from that by the strlen() of the string literal.  // and here's what it does:  bool operator() (char c) const {    // Return whether or not 'c' is found within the string owned by this    // instance of the class.    return find(theList.begin(), theList.end(), c) != theList.end();  }};string userInput() {  string input; // Another hint: give it a meaningful name :)  getline(cin, input); // when your names make sense, the comments aren't really  // necessary any more.  // We use std::remove_if() - see http://www.sgi.com/tech/stl/remove_if.html  // and then the version of std::string::erase() which takes two iterator  // parameters. This powerful combination is known as the erase-remove idiom.  // Basically, remove_if() shifts all the undesired stuff to the end, with a  // quick, clever algorithm, and tells us where the real string ends and the  // undesired stuff begins - then we tell erase to erase from there to the end.  input.erase(    remove_if(input.begin(), input.end(),charIsIn("`~!@#$%^&*()-_=+|}][{';:/?.>,<\\\"")),    input.end()  );  // Now we can transform...  transform(input.begin(), input.end(), input.begin(), toupper );  return input;}You can see how this generalizes if we need to strip other sets of characters from strings elsewhere in the code - just make the same erase and remove_if calls, using a charIsIn constructed using whatever other string. We can generalize still further by making a templated isIn<T> class rather than the specific charIsIn (this is why I illustrated it using a vector for storage and the free "find" algorithm, rather than a string and its find() member function - that way doesn't generalize so neatly for other types. Then again, that constructor doesn't either, so...). We could also get more char-specific and optimize the guts of charIsIn by building a lookup table (like bool[256], where a character's value is used as an index into the table). We could also get more specific to what we're actually doing, after understanding how the remove_if and transform algorithms work, by rewriting it ourselves to do both things at once - and it might even be faster; but you should always look for the simple ways first. Oh, and if we only needed to remove a single specific character (e.g. remove all '#'), we could use the simpler 'remove' rather than 'remove_if'.For parsing stuff, there are again some more sophisticated tools available:// This version splits on any white space. It is *not* easy to adapt this to use// a custom delimiter character, or to enforce a single character separation.// For those situations I would honestly just write the loop. But:vector<string> parseInput (const string& input, char delim ) {  vector<string> result;  // by the way, passing the delimiter as the second parameter for the  // istringstream constructor doesn't do what you think/want :(  copy((istream_iterator<string>(istringstream(input))),  istream_iterator<string>(),  back_inserter(result));  return result;  // The extra parentheses are necessary there because of a stupid C++ syntax  // rule - otherwise, it is possible to interpret the whole thing as a very  // complicated function declaration. Actually, not sure that's true in this  // case, but there certainly are similar cases where it can bite you. Sigh.}Oh and finally: consider putting your functions before main in the file, so that you don't have to forward-declare them. :)   