The purpose of this question set is to give you a chance to focus your knowledge of the string class in C++.
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!
The string class contains the functions _____, _____, and _____ to search for substrings, characters not in another string, and characters in another string respectively.
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. |
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.
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!
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); }
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]); }
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!)
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..?)
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!!!
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.)
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); }
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 ("").
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.
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.)
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.)
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.