Topical Information

The purpose of this question set is to give you a chance to focus your knowledge of the string class in C++.

Question Set Information

Questions

  1. What does concatenation mean? What operation(s) are used to concatenate strings? Can we concatenate two literal strings? What about two literal characters?

    
            Concatenation is the process of attaching one thing to another.  In
            this situation, we are talking about attaching one string to the
            end of another string.
    
            We can use the + operator to concatenate two strings to form a
            new string having their joined content — without harming
            either of the original strings in the process!
    
                s = "Hello ";
                t = "World";
                cout << s + t;   // prints "Hello World"
                // s == "Hello " && t == "World"
    
            Or, we can use the += operator to join one string onto the end
            of another string — altering the one listed on the left of
            the 'assign-with-addition' operator.
            
                s = "Hello ";
                cin >> t;  // user types "Joe"
                s += t;          // s == "Hello Joe"
    
            We cannot concatenate two literal strings directly to one another.
            Instead, we must concatenate a string class object to one
            literal string and then we can concatenate this result to the
            second literal string.
    
                s = "Hello " + "World";   // ILLEGAL!!!
    
                s = "Hello ";
                s += "World";             // okay in two steps...
    
            Likewise we cannot concatenate two literal characters.  But this
            one is even worse because it may appear at first to work.  Again, the
            rule is that an actual string class object must appear as one
            of the first two items in a concatenation in order for it to succeed!
    
    
  2. The string class contains the functions _____, _____, and _____ to search for substrings, characters not in another string, and characters in another string respectively.

    1. find, find_first_of, find_last_ofNO
    2. find_first_not_of, find, find_first_ofNO
    3. find_first_of, find_first_not_of, find_last_ofNO
    4. find, find_first_not_of, find_first_ofYES
    5. find_last_of, find_last_not_of, findNO
  3.  
    TRUE/FALSE Many actions on strings can be done all at once (like input, output, assignment, concatenation, etc.).
    TRUE/FALSE But when we want to do something novel (capitalization, for instance), we must use a loop to process each character individually.
    TRUE/FALSE To do this individual processing, we can use a for loop controlled by a string::size_type index which will stop before we reach the string's length/size.
  4. The integral values used to indicate positions in a string count from _____. Likewise, the values used with functions like insert, replace, and erase to indicate position and number are _____-based. We should use care not to mis-count here or we could insert _____ the character we wanted to insert before, erase the wrong set of characters (one _____ of where we wanted), or replace a set of characters that is just to the _____ of the ones we wanted to replace.

    1. one, zero, before, left, rightNO
    2. one, one, in front of, left, leftNO
    3. 1, 2, behind, right, leftNO
    4. zero, zero, after, right, rightYES
    5. 0, 1, left of, left, rightNO
  5. The string::assign() function will overwrite the 'calling' string with the specified sub-string of the argument string. This could also be accomplished by using the assignment (=) operator with a call to substr on the right side.

    Similarly, the string::clear() function could be substituted with a call to erase starting at    0    and ending at string::size(). We could also use the string::erase() function and pass it 0 and string::length() as its two arguments.

    This seeming redundancy in the string class design gives the programmer wanting to use strings the flexibility/ability to perform an action the way she sees it being done. The 'redundant' functions are most likely written in terms of one another so that there isn't really any redundancy in the code after all.

  6. Although the getline function is great when we want to read a string that contains blank spaces, it does have a slight drawback. When it is called immediately following an extraction (>>) operation ('immediate' with respect to cin's view of the world, that is), it will input a blank string ("") string — hardly what the user wanted to give us. To fix this problem, we must do several things before we call getline. First we must flush cout. This is because our next action will be to peek cin — and some library implementors fail to have cout print prompts if they aren't 'really' reading input. If we see a new-line ('\n') character, we know that we'll fall into the trap outlined above. When this happens, we call cin.ignore() to effectively skip over that character. This should give us a fresh start for our call to getline!

  7. Show code that will locate any occurrences of "Robert" in a string and substitute "Bob" for them. (It seems that Robert is coming off as a 'stuffed-shirt' around the office and needs to look more common and friendly.)

    
            string s;
            string::size_type p;
    
            p = s.find("Robert");
            while (p < s.size())
            {
                s.replace(p, 6, "Bob");
                p = s.find("Robert", p+3);
            }
    
    

    Now show how you would have the substitution alternate between "Bob" and "Rob". (This will make Robert seem more approachable, too. *grin*)

    
            string s;
            string::size_type p;
            bool bob;
    
            bob = true;
            p = s.find("Robert");
            while (p < s.size())
            {
                s.replace(p, 6, bob ? "Bob" : "Rob");
                bob = !bob;
                p = s.find("Robert", p+3);
            }
    
    
  8. Write code which can change a (single) string to all uppercase.

    
            for (string::size_type c = 0; c != str.length(); c++)
            {
                str[c] = toupper(str[c]);
            }
    
    
  9. Explain what is wrong (if anything) in each of the following code fragments. (Note: These are fragments! You may assume everything around — most especially before — the fragment is working fine. If anything is wrong, it will be in the lines presented!)

    1.     string s;
          cout << "Enter string:  ";
          cin >> s;
          s = toupper(s);
          cout << "\n\nThat's '" << s << "', right?\n";
      
      
              The toupper function from cctype is only for individual
              characters — not for strings!
      
              (Maybe I could place the loop from the question above into my
              own function..?)
      
      
    2.     string s = "Hello";
          s[5] = '!';
          cout << s << endl;
      
      
              The string s is only 5 characters long.  Therefore,
              valid positions into this string are between 0 and 4
              — inclusive.  We are trying to store this exclamation mark into
              a position which does not exist!  Only bad things could result from
              this!!!
      
      
    3.     if ("hello" == "Hello")
          {
              cout << "The world's gone mad!!!\a\n";
          }
          else
          {
              cout << "Oh, well, then that's all right, then...\n";
          }
      
      
              Firstly, these two string values will never be equal so
              the branch is a waste of code.  (One has lower-case h and
              the other has upper-case H!)
      
              Secondly, comparison only works for actual string class
              objects — not for literal strings!  Both of these are
              literals and so this comparison won't do what we even want!
      
              (If you put it in a main and try it, you'll find that it
              works, but it isn't working correctly.  It is comparing the
              place in memory where the two literals are stored and reporting
              whether they are at the same place or not.  We would have liked
              it to report if they had the same content or not, of course.)
      
      
    4. s is a string

          while (s.find("howdy") == string::npos)
          {
              s.replace(s.find("howdy"), 5, "hi");
          }
      
      
              The string::find() function returns the value
              string::npos when it does NOT find
              the desired value.  Were we to repeatedly loop while not
              finding what we wanted, we'd be idiots.  Change the == to
              !=.  (Using this illegal position in a replacement operation
              would undoubtedly go awry too!)
      
              Another 'fix' would be to cache the find result in a variable
              for use in both the loop test and the replace argument.  This
              could further speed things up by having the second find start
              after the text we've just put into place:
      
                  p = s.find("howdy");
                  while (p != string::npos)
                  {
                      s.replace(p, 5, "hi");
                      p = s.find("howdy", p+2);
                  }
      
      
    5.     string s;
          char t;
          cout << "Enter 'A':  ";
          cin >> t;
          cout << "Enter a line of text:  ";
          getline(cin, s);
      
      
              Here we see an example of the situation discussed above in
              fill-in-the-blank form.  From cin's perspective, an
              extraction operation (>>) is immediately followed
              by a getline function call.  s will always end up
              with an empty string value ("").
      
      
    6.     string s, t;
          t = "";
          getline(cin, s);
          while (!s.empty())
          {
              t += '\n' + s;
              getline(cin, s);
          }
          s.assign(t, 1, t.length());
          s += '\n';
      
      
              There is nothing wrong with this code.
              
              Some might prefer the new-line processing be flipped to avoid the
              call to assign after the loop, but it isn't really a problem.
      
      
  10. A common security breech is caused by entering more text than a prompt can handle. This allows the attacker to corrupt memory in such a way as to gain 'super-user' or 'administrator' access privileges. Is it possible for this to happen with the string class used to read in text? Why/Why not?

    
            Not really.  The string class allows its content to
            grow as large as the user desires.  It can never be overrun.
    
            On the other hand, it can out-grow the memory on the system.
            This could lead to the system shutting down entirely —
            a.k.a. a DoS or "Denial of Service" attack.  But, in order
            for this to happen, the attacker would have to enter many
            gigabytes of data (more than physical RAM — they'd have
            to nearly fill the virtual memory provided by the OS as well)!
            It would seem pretty unlikely.  (And, this kind of attack
            doesn't allow the attacker to gain access.  It just shuts down
            the machine so no one can benefit from its services.)
    
    
  11. When we need to have whole words or lines as data, the string class is great. But when we just need a y/n or single digit/letter menu response, we still use char. Briefly explain why this is so. (There are multiple reasons. Tell all you can muster.)

    
            
    • the important data doesn't need so much storage so why waste lots of memory on a string
    • it is cheaper/more efficient to compare character data than it is to compare string data
    • ...

    What do we do when the user types a word or line when we just wanted a single char? Won't that cause input stream problems later on?

    
            We can still allow the user to enter whole words (or even lines) by
            using cin's ignore facilities.