.. _strings: Loops and Simple Strings ======================== In this lecture, we will be exploring string processing. We will also look a bit more closely at loops, since many of our example programs use loops in processing strings. More on Loops ------------- As we saw in our earlier studies, we use loops when we need to do something over and over. In our discussion on basic structures, we showed how to build loops using the simple structured *flowchart* forms - the **while-statement** or the **do-statement**. These loops are really all that is needed to build programs that repeat an action a number of times. Reviewing the While Loop ,,,,,,,,,,,,,,,,,,,,,,,, We can loop over a number of items - say our days of the week - by setting up a simple while-statement: .. code-block:: c int day; ... day = 1; while (day < 8) { cout << "Processing day " << day << endl; day = day + 1; } This simple loop sets up a controlling counter (**day**), gives it an initial value (designed to make the loop start!) and then does some work (our output statement). Finally, at the end of the loop, it adds one to the counter and goes back to the top to see if we need to process another day. Here is the output: .. code-block:: bash Processing day 1 Processing day 2 Processing day 3 Processing day 4 Processing day 5 Processing day 6 Processing day 7 Press any key to continue . . . Now, suppose we want to add up something as we process the loop. To make the code easy, let's just add up the day numbers we are using for our counter - you know: 1+2+3+4+5+6+7. To do this, we need another variable to collect the answer. We will *accumulate* the total as we spin through the loop. We need to start off by setting our new variable to zero, then, on each pass through the loop, we will add in the counter for that pass. Like this: .. code-block:: c int sum = 0; ... day = 1; while (day < 8) { sum = sum + day; cout << "Processing day " << day << " (sum is " << sum << ")" << endl; day = day + 1; } cout << "The final value for sum is " << sum << endl; Which gives us: .. code-block:: bash Processing day 1 (sum is 1) Processing day 2 (sum is 3) Processing day 3 (sum is 6) Processing day 4 (sum is 10) Processing day 5 (sum is 15) Processing day 6 (sum is 21) Processing day 7 (sum is 28) The final value for sum is 28 Press any key to continue . . . Do you see how the accumulator is built up as we run through the loop. This is a common way to build up an answer is small stages. You use this pattern all the time in programming. Now, let's introduce our new looping statement and make this easier: The For Statement ,,,,,,,,,,,,,,,,, We can simplify all of our logic for counting our way through a loop by using the *for-statement*. Here is what it looks like: .. code-block:: c for(int day = 1;day < 8; day = day + 1) { cout << "Processing day " << day << endl; } This works exactly like the example above which used the *while-statement* to do the job. The *for loop* is controlled by the stuff inside the parentheses immediately after the for. The Loop Counter ................ This section of the statement consists of three parts, separated by semicolons. The first part sets up the loop counter (**day** in this case). Notice that we have declared the counter here. This actually creates a new container as we enter the loop. If we already had a counter set up, we could use that variable instead (leaving off the int) However, sometimes it is easier to just invent a counter as you need it. Also, if you already have a variable in your program with the same name - and you invent a new container like this, your old container will be hidden inside the loop and left untouched! There is one big issue with declaring the counter inside the *for-statement* - it evaporates when you leave the loop. If you try to see what value is in the counter day after to closing curly bracket - the compiler will pitch a fit! .. code-block:: c for(int day=1;day<8;day=day+1) ... } cout << day << endl; Boom! This will not even compile. .. warning:: Microsoft seems to think this is wrong, so they changed the rules and let you continue to use the counter. Unfortunately, this means code written for Microsoft compilers will not work on anyone else's compilers. It's good to be the king! The Loop Condition .................. The second part of the control section determines how long we stay in the loop. The logical expression we place in this section works exactly like the logical expression we placed in the while part before. The expression is evaluated at the end of all the work inside the loop (inside the curly braces). If the expression evaluates to true we keep looping, if it evaluates to false we exit the loop. Updating the Counter ..................... The last part of the control section tells the system what to do to modify the counter when the statement reaches the end of the loop. Normally, you modify the loop counter to set its value for the next pass. The loop body ............. Anything you need to do on each pass through the loop is surrounded by the curly braces (and indented). This is much easier to understand than setting things up manually, but it works the same way. In fact, there is no magic flowchart diagram for this statement - just the normal while-loop diagram. For Loop Funnies ................ There are some interesting forms of the *for-statement* that you run into. All three of the control sections are optional - huh? That means you do not need to set up a loop counter, check it or modify it in the control section. You could do all of that outside this section and things would work fine. Except the statement would never end! .. code-block:: c for(;;) { cout << "This is never going to stop!" << endl; } How would we ever get out of this mess? Here is a way! .. code-block:: c day = 0; for(;;) { cout << "This may never stop!" << endl; day = day + 1; if (day == 5) break; } The **break** statement is a new statement we seldom use except in special cases like this. It jumps to the end of the enclosing loop statement: .. code-block:: bash This may never stop! This may never stop! This may never stop! This may never stop! This may never stop! Press any key to continue . . . String data ----------- Now, let's explore a new data type - the string. Suppose you want the user to enter information for each day during the week, and you need for them to tell you the day they are working with. How do we go about getting the day when it is a bunch of characters typed on the keyboard. C++ supports a data type called a *string* which we can access if we add another **#include** line in our programs: .. code-block:: c #include ... string weekday; .. note:: It appears that the string data type is now being made available in ``iostream``. You will see this include line often in existing code, so I recommend that you add it if you intend to use the string dtaa type in your code. This fragment sets up a container that can hold a number of characters. (How many? As many as you need - it is an interesting container!) We have been using strings already, however, only to display text on the screen. Those sequences of letters inside double quote characters are actually strings. We can put those strings into our new container. In this case every character except the surrounding double quote characters gets saved in the container: .. code-block:: c weekday = "tuesday"; Simple, just put the string in quotes as shown. Be careful here, though, the exact case of the characters matters! Misspell a value and the system will not use it correctly! Reading a string ,,,,,,,,,,,,,,,, Once we know that the string can store characters, we can read in a sequence of characters from the user typing at the keyboard (up to the final return) very easily: .. code-block:: c #include #include int main(int argc, char *argv[]) { string weekday; weekday = "tuesday"; cout << "What day is this?"; cin >> weekday; if (weekday == "tuesday") cout << "It is " << weekday << endl; system("PAUSE"); return EXIT_SUCCESS; } which gives this if I type in **tuesday** (and spell it correctly)! .. code-block:: bash What day is this?tuesday It is tuesday Press any key to continue . . . We would like to be able to ask questions about the string, and check if we have a certain value. There is a minor problem with this, though. Users (remember - those folks who never do anything the way you expect them to) will type in things like a week day name in upper case, lower case, mixed case, and even misspell the darned things. So how do we handle all of this? Well, the computer is not smart enough to handle that for you, but we have enough tools available to do the job. It just takes a bit of work! Checking the string ,,,,,,,,,,,,,,,,,,, If the user typed in a bunch of characters, we may need to figure out what they typed in. We can use our normal comparison operators to ask! However, we will need to match what they typed in exactly. For now, we will assume they enter the day name in all lower case letters (perhaps you should tell them to do this with a prompt message). Later, we will learn how to modify the user's string so it is easier to work with! .. code-block:: c #include string weekday; cout << "What day is this (in lower case)? "; cin >> weekday; if(weekday == "monday") cout << "Bad day" << endl; else cout << "At least it's not monday!" << endl; .. code-block:: text What day is this (in lower case)? tuesday At least it's not monday! Press any key to continue . . . To handle an entire week's worth of data, we will need to use nested if-statements to figure out what day we have: .. code-block:: c if (weekday == "monday") { cout << "Work!" << endl; } else if (weekday == "tuesday") { cout << "Work!" << endl; } else if (weekday == 'wednesday") { cout << "Work!" << endl; } Boy, this will get old for a long list of possible values. There are easier ways to handle this, but we need more background before we can use them. Once again, for now, just use the features of your editor to type in all the values. Let's try something a bit different here, though. Let's assign a numerical value (an integer) to each day based on the name the user types in. Here is the code to do that: .. code-block:: c int day_number; if (weekday == "monday") day_number = 1; else if (weekday == "tuesday") day_number = 2; else if (weekday == "wednesday") day_number = 3; else if (weekday == "thursday") day_number = 4; else if (weekday == "friday") day_number = 5; else if (weekday == "saturday") day_number = 6; else if (weekday == "sunday") day_number = 7; else day_number = 0; cout << "Your day is day " << day_number << endl; Remember, we can leave off all those curly braces if we are only using a single statement for each part of the *if-statement*. Does this look right in this case? Only the compiler knows for sure! .. code-block:: bash What day is this (in lower case)? tuesday Your day is day 2 Press any key to continue . . . The Switch Statement -------------------- Now that we have a simple integer value available for each week day, we can use this value in a simple new statement to do something specific for each day of the week. This new statement is the *switch statement*. .. code-block:: c switch(day_number) { case 1: cout << "4 more days til Friday!" << endl; break; case 2: cout << "3 more days til Friday!" << endl; break; case 3: cout << "2 more days til Friday!" << endl; break; case 4: cout << "1 more days til Friday!" << endl; break; case 5: cout << "1 more day til Saturday!" << endl; break; } .. code-block:: bash What day is this (in lower case)? tuesday Your day is day 2 3 more days til Friday! Press any key to continue . . . Now, this looks interesting. We have one part that evaluates the variable (**day_number**) and determines what value it currently contains. Then, the statement checks the list of case values, looking to see which one matches the value in day_number. When if finds the right value, it processes the statements after the colon and up to the next case (or the close brace). Phew! The **break** statement is needed to make the statement do only one thing for each value. **Break** causes the computer to jump to the end of the statement and continue on. If you forget the **break**, the statement will fall through to the next case and continue doing the statements in that section - which is sometimes handy, but more often just wrong! Here is an example where we can use that feature: .. code-block:: c case 1: case 2: case 3: case 4: case 5: "cout << "work" << endl; default : cout << "sleep in" << endl; } Notice the new entry here - **default**. If the value in day_number does not match any of the values on the **case** lines, you end up processing the code in the **default** section. If you do not provide a default section, you will just do nothing if the value does not match one of the case values. Try this: .. code-block:: c int days; days = 0; switch(day_number) { case 1: days = days + 1; case 2: days = days + 1; case 3: days = days + 1; case 4: days = days + 1; cout << days << " more day's til Friday!" << endl; break; case 5: cout << "1 more day til Saturday!" << endl; break; default : cout << "Sleep in!" << endl; } Here I left off the breaks on the first few lines , and let the program fall through to calculate the number of days until Friday! The **break** statements left in were needed to stop the program from running code I did not want processed. Here is the output: .. code-block:: text What day is this (in lower case)? wednesday Your day is day 3 2 more day's til Friday! Press any key to continue . . . Phew, that is enough new stuff for today! .. vim:set filetype=rst spell: