Computer Science 111, Assignment 4
Introductory tutorial on while loops
- Preliminaries
- Finding the length of a C-string using nested if/else
- cin's getline function vs. cin's extraction operator with C-strings
- Finding the length of a C-string using a while loop
- while loop checklist
- Counting letters in a C-string
- Another example of why we need loops
- Order of statements in a loop, and other variations in loop design
- Inputting a sequence of numbers on separate lines vs. inputting all the numbers on one line
- Named constants vs. multiple uses of a literal
- Count-controlled repetition with an endpoint decided at runtime
- Arithmetic assignment operators and increment/decrement operators
- Scope and duration of variables
- Avoiding division by zero
- Code traces with while loops
- Preliminaries.
To ensure that you have enough disk space, please be sure to get rid of all a.out, l.out, and core files before you begin. To find where they are, type the following at the "forbin>" prompt, in your home directory:find . | grep a.out find . | grep l.out find . | grep coreThen go to the indicated directories and remove the files.
Also, remove old homework source code files after first backing them up (via FTP) onto more than one diskette.
Then, if you have not done so already, create a directory named hw04 inside your homework directory. Then change your present working directory to hw04 and copy into it the example files for Assignment 4, as follows:
cp ~nixon/cs111/hw04/* .
- Finding the length of a C-string using nested if/else.
You have already been taught how to determine the length of a C++ string class object. To that end, you can use the length function of the string class, as in the following example code segment:cout << "Enter any word:> "; string word; cin >> word; cout << "The word you entered contains " << word.length() << " characters." << endl;But how can we determine the length of a C-string?
Recall that a C-string is implemented using an array of characters. And recall that an array cannot remember its own lenght. But the end of a C-string is marked by a null character, as explained in the Tutorial on characters and strings - brief intro in Assignment 2.
Therefore, to determine the length of a C-string, we must determine where the null character is. We must chack each location in the array, starting at the beginning of the C-string, until we find the null character.
This can be done using nested if/else. Below is one way to find the length of a C-string stored in line, an array of 21 characters - which can, therefore, store a C-string of maximum length 20 characters, not counting the null character:
int length; if ( line[0] == '\0' ) length = 0; else if ( line[1] == '\0' ) length = 1; else if ( line[2] == '\0' ) length = 2; else if ( line[3] == '\0' ) length = 3; else if ( line[4] == '\0' ) length = 4; else if ( line[5] == '\0' ) length = 5; else if ( line[6] == '\0' ) length = 6; else if ( line[7] == '\0' ) length = 7; else if ( line[8] == '\0' ) length = 8; else if ( line[9] == '\0' ) length = 9; else if ( line[10] == '\0' ) length = 10; else if ( line[11] == '\0' ) length = 11; else if ( line[12] == '\0' ) length = 12; else if ( line[13] == '\0' ) length = 13; else if ( line[14] == '\0' ) length = 14; else if ( line[15] == '\0' ) length = 15; else if ( line[16] == '\0' ) length = 16; else if ( line[17] == '\0' ) length = 17; else if ( line[18] == '\0' ) length = 18; else if ( line[19] == '\0' ) length = 19; else // if ( line[20] == '\0' ) length = 20;But what would happen if the size of the array of characters were, say, 1001 characters instead of 21 characters? Then the nested if/else would get awfully long, not to mention awfully tedious to type.
As we will see later, there is another, much better way to find the length of a C-string, such that the length of the program itself stays the same regardless of the size of the array which stores the C-string.
- cin's getline function vs. cin's extraction operator with C-strings.
For two examples of complete programs which find the length of a C-string using the above method, see lengthCString1A.cpp and lengthCString1B.cpp. These two programs are the same, except that lengthCString1A.cpp uses cin's extraction operator (>>) to input the string, whereas lengthCString1B.cpp uses cin's getline function instead. The difference between the extraction operator and the getline function is as follows:
- The extraction operator refuses to read any whitespace characters into a string variable. (Whitespace characters are the space (' '), the tab ('\t'), the carriage return ('\r'), and the newline (\n).) If s string begins with whitespace characters, the extraction operator will skip over them and start reading at the first non-whitespace character. It will then continue reading all subsequent non-whitespace characters up to, and not including, the next whitespace character.
For example, given the following string, beginning with a bunch of spaces or tabs:
cat dog birdThe extraction operator will read only the string "cat" without any leading spaces.
- The getline function will read an entire line of text, regardless of whether or not it contains whitespace.
When using the getline function, you must specify the length of the array into which the characters are being read. Example:
char line[21]; // 20 characters plus the null character cin.getline(line, 21); // Reads a line of text, // including whitespaceWhat happens if, when prompted to enter a line of text, you just hit [Enter] without typing any characters? In that case, the getline function reads an empty string, i.e. a string with length 0.
On the other hand, the extraction operator refuses to read an empty string. If you hit [Enter] repeatedly, the program will wait until you enter a line of text containing at least one non-whitespace character. It will then read the first continuous sequence of non-whitespace characters on that line.
Now look again the big long nested if/else's in the programs lengthCString1A.cpp (which uses the extraction operator) and lengthCString1B.cpp (which uses getline).
If a C-string is empty, the null character is at location 0 in the array. Therefore, because the getline function can read an empty string, the program which uses getline must begin searching the string for the null character at location zero. On the other hand, because the extraction operator cannot read an empty string, it can never put a null character at location 0 in the array. Therefore, in the program which uses the extraction operator, the big long nested if/else begins searching for the null character at location 1 rather than at location 0.
- Finding the length of a C-string using a while loop.
Look again at lengthCString1A.cpp and lengthCString1B.cpp, our two programs which determine the length of a C-string using a big long nested if/else. In both programs, observe that the big long nested if/else performs a repetitive job. Over and over again, it checks locations in the C-string to see if a given location contains a null character. At each location, if the null character has been found, then the program has thereby determined the strong, and, in that case, the program checks no further locations. On the other hand, if the null character has not yet been found, then the program checks the next location.Not only does the program do a repetitive job when executed, but the big long nested if/else is, itself, a very repetitive sequence of lines of C++ code.
It would be much better to use a programming construct that specifies a repeated task only once, without repeating similar lines of code. Such a programming construct is known as a loop.
There are three kinds of loops in C++. We will now look at the simplest kind of loop, a while loop.
Look now at lengthCString2A.cpp and lengthCString2B.cpp, two programs which determine the length of a C-string using a while loop. In lengthCString2A.cpp, the program searches for the null character as follows, starting at location 1 (because a string entered using the extraction operator cannot be empty):
// Prepare to search for a null character at the // first possible location in line: int length = 1; // Check each consecutive location in line // until a null character is found: while ( line[length] != '\0' ) length = length + 1;In lengthCString2B.cpp, the program searches for the null character as follows, starting at location 0 (because a string entered using the getline function can be empty):
// Prepare to search for a null character at the // first possible location in line: int length = 0; // Check each consecutive location in line // until a null character is found: while ( line[length] != '\0' ) length = length + 1;A while loop consists of the word while followed by an expression in parentheses known as the condition, followed by one or more statements which are executed repeatedly as long as the condition is true.
The statement or statements to be executed repeatedly are known as the body of the loop. In our present example, the body consists of only one statement:
length = length + 1;If the condition is false the first time, the body of the loop is never executed.
In our present example, the one statement in the loop body adds 1 to the current value of length. By increasing length by 1 repeatedly, the program is able to look at successive locations in the array each time the condition is checked. The loop stops executing when the null character is found.
Make sure you understand the difference between if and while. Both if and while loops have bodies (dependent statements) that are executed only if the condition in parentheses is true. However, the body of an if structure is executed only once, if at all, whereas the body of a while loop is executed repeatedly until the condition becomes false.
Each repetition of the body of a loop is known as an iteration of the loop. (The word "iterate" means "repeat.")
- while loop checklist.
Examine carefully the while loop in our example and verify that it satisfies the following checklist of five things you must always remember when writing a while loop:
- Include a condition in parentheses next to the word while. The condition is an expression whose value is either true or false. Often, though not always, it tests the value of one or more variables. The loop will continue iterating as long as the condition is true. Make sure the condition is suitable in terms of when you want the loop to stop.
- Make sure that the variable(s) tested in the while condition has been given a value BEFORE the while loop body is executed the first time. Otherwise the loop's condition will be checking garbage, with unpredictable results.
- Make sure that the value of at least one variable tested in the while condition is changed somewhere within the body of the loop, and that the change is of a kind such that the loop condition will eventually become false. Otherwise, you'll have an infinite loop, and the program cannot terminate.
- When the body of the loop contains more than one statement, use curly braces to indicate the beginning and end of the loop body. (See examples further down on this page.) Curly braces are not needed when the loop body contains only one statement.
- Whether or not you need curly braces, always INDENT the loop body by one level of indentation (at least 3 spaces) beyond the indentation of the block of code in which it occurs. The while loop heading and closing curly brace should NOT be indented with the loop body; their indentation should be the same as the surrounding block of code. (Indentation affects only the program's readability to human programmers, not its actual working. But readability IS important and a significant factor in your grade.)
Keep a copy of this tutorial for future reference and have it with you when you do your homework, so you can refer to the checklist when writing loops.
- Counting letters in a C-string.
Consider now the problem of determining how many letters there are in a C-string which contains not only letters but also other characters, such as digits and punctuation marks.We will need to write another program which examines each character in a string. For each character in the string, this program should determine whether the character is a letter, and, if so, it should add 1 to a count of the number of letters in the string. To outline this informally as an algorithm, before we start writing C++ code:
For each character in the string, if the character is a letter, add 1 to count of letters.This will work only if our count of letters begins at zero. Also, of course, we will need to input the string at the beginning, and we will need to output the result when we are finished. So here's a more complete outline of our algorithm:
Input a string text. Let count of letters = 0. For each character in text, if the character is a letter, add 1 to count of letters. Output count of letters.As an additional user-friendly nicety, we should also echo the string after inputting it.
We already know how to do input and output. Let's now figure out how to do the more interesting parts of this program.
How do we determine whether a character is a letter? Recall how we did this in classifyChar1.cpp and classifyChar2.cpp in Assignment 3:
else if ( (entry >= 'A' && entry <= 'Z') || (entry >= 'a' && entry <= 'z') ) cout << "an ASCII letter." << endl;(See the Assignment 3 Tutorial on characters, strings, and debugging.)
In the program we are writing now, we must examine each character in the string until the null character is reached.
Look now at countLetters.cpp. Below are the interesting parts:
// No letters have been found YET: int countLetters = 0; // Count letters: int index = 0; // Start at the beginning of the string. while ( text[index] != '\0') // until end of string { // If the character at index is a letter, add one // to count of letters. Then, whether or not the // character is a letter, prepare to look at the // next character. if ( (text[index] >= 'A' && text[index] <= 'Z') || (text[index] >= 'a' && text[index] <= 'z') ) countLetters = countLetters + 1; index = index + 1; } // while
- Another example of why we need loops.
One of the Assignment 1 example files was averageOf3.cpp, which found the average of 3 integers. Suppose we now want write a program to find the average of 10 numbers, and suppose the program is required to ask the user for only one number of time (e.g. to be compatible with a script file like our homework script file). We could prompt the user for 10 inputs, as follows:cout << "Enter an integer:> "; int number1; cin >> number1; cout << "Enter an integer:> "; int number2; cin >> number2; cout << "Enter an integer:> "; int number3; cin >> number3; cout << "Enter an integer:> "; int number4; cin >> number4; cout << "Enter an integer:> "; int number5; cin >> number5; cout << "Enter an integer:> "; int number6; cin >> number6; cout << "Enter an integer:> "; int number7; cin >> number7; cout << "Enter an integer:> "; int number8; cin >> number8; cout << "Enter an integer:> "; int number9; cin >> number9; cout << "Enter an integer:> "; int number10; cin >> number10; int sum = number1 + number2 + number3 + number4 + number5 + number6 + number7 + number8 + number9 + number10; float average = (float) sum / 10;Let's now think of various ways to improve this program. In the first place, we don't need ten separate variables to hold all the numbers to be added. We can use just one variable for this purpose, as follows:
int sum = 0; int number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; cout << "Enter an integer:> "; cin >> number; sum = sum + number; float average = (float) sum / 10;The above code segmant uses only three variables: number, sum, and average, whereas the previous version used twelve variables.
Here, sum is being used to hold a cumulative sum. As each number is input, it is stored temporarily in the variable number, then added to sum. After we have added all the numbers to sum, then sum is equal to all the numbers we have added to it. In order for this to work, sum must be initially zero before we start adding numbers to it.
We need only one variable, number, in plase of all the variables number1, number2, ... , number10, because, after a number has been added to sum, there is no need to keep track of the number's value anymore. So, the variable number can be re-used to input the next number.
However, the above program segment repeats the following three statements ten times:
cout << "Enter an integer:> "; cin >> number; sum = sum + number;It would be nice if we could abbreviate the repetition by writing something like this:
int sum = 0; int number; Do 10 times: { cout << "Enter an integer:> "; cin >> number; sum = sum + number; } float average = (float) sum / 10;The above is NOT valid C++ code. It is a form of pseudocode, which we are now using as a preliminary step in developing an algorithm.
Fortunately, in C++, we can indeed write something very much like our pseudocode, though not quite as simple. There are indeed program constructs which allow us to write a statement or block only once, but to have the program execute the statement or block repeatedly, however many times we want. Such constructs are called loops.
In a program which finds the average of 10 numbers, a loop would save us the trouble of typing ten identical sequences of three statements each. Thus, a loop lets us write the program with fewer lines of code.
Let us now think about what is necessary in order to repeat a statement or block some fixed number of times. The statement or block to be repeated is known as the loop body. Somehow, the program must keep track of how many times the loop body has been executed. To that end, a separate variable must be used to count iterations (number of times the loop body is executed). Before any repetition begins, the count variable must be given an initial value. The count variable then counts iterations. And, before each iteration of the loop body, the program must somehow test the value of the count variable to determine whether enough repetitions have occurred. When enough repetitions have occurred, we want the program to stop telling the machine to repeat the loop body.
Thus, expanding our pseudocode a bit, the desired repetition could be accomplished as follows:
int sum = 0; int number; int count = 0: Repeat as long as count < 10: { cout << "Enter an integer:> "; cin >> number; sum = sum + number; count = count + 1; } float average = (float) sum / 10;Using a while loop, a C++ equivalent of the above pseudocode would be:
int sum = 0; int number; int count = 0; while ( count < 10 ) { cout << "Enter an integer:> "; cin >> number; sum = sum + number; count = count + 1; } float average = (float) sum / 10;The above loop, with comments added, is used in our example program average1A.cpp.
- Order of statements in a loop, and other variations in loop design.
Often, there is more than one correct way to write a loop which accomplishes a given task. For example, consider again the while loop in our example above:int sum = 0; int number; int count = 0; while ( count < 10 ) { cout << "Enter an integer:> "; cin >> number; sum = sum + number; count = count + 1; }In this particular example, we could rearrange the order of statements in the loop as follows, without changing, in any way, what the program accomplishes:
int sum = 0; int number; int count = 0; while ( count < 10 ) { count = count + 1; cout << "Enter an integer:> "; cin >> number; sum = sum + number; }Thus, in this particular example, it doesn't matter whether we add 1 to the count before or after we input number and add it to sum.
On the other hand, consider again the loop in countLetters.cpp:
int countLetters = 0; int index = 0; while ( text[index] != '\0') { if ( (text[index] >= 'A' && text[index] <= 'Z') || (text[index] >= 'a' && text[index] <= 'z') ) countLetters = countLetters + 1; index = index + 1; }What would happen if we were to rearrange the order of statements in the loop, as follows?
int countLetters = 0; int index = 0; while ( text[index] != '\0') { index = index + 1; if ( (text[index] >= 'A' && text[index] <= 'Z') || (text[index] >= 'a' && text[index] <= 'z') ) countLetters = countLetters + 1; }This won't work correctly because the first character to be looked at by the if statement will now be the character at location 1 in the array, rather than the character at location 0. Thus, the program will fail to count a letter at location 0.
We could fix this problem by initializing index to a value of -1 instead of 0:
int countLetters = 0; int index = -1; while ( text[index] != '\0') { index = index + 1; if ( (text[index] >= 'A' && text[index] <= 'Z') || (text[index] >= 'a' && text[index] <= 'z') ) countLetters = countLetters + 1; }but this is a very inelegant fix, not nearly as readable as our original version, in which we initialized index to zero and increased its value by 1 after processing the character at that position.
Consider again our example program which averages 10 numbers:
int sum = 0; int number; int count = 0; while ( count < 10 ) { cout << "Enter an integer:> "; cin >> number; sum = sum + number; count = count + 1; }Observe that the loop counts from 0 up to and including 9, so that the loop body is executed a total of 10 times. (We say that the loop iterates 10 times.) In this particular example, we could also have it count from 1 up to and including 10, instead, and the program would still work just as well.
Alternatively, it could count down from 10 to 1, inclusive:
int sum = 0; int number; int count = 10; while ( count >= 1 ) { cout << "Enter an integer:> "; cin >> number; sum = sum + number; count = count - 1; }For that matter, it could count from 30 down to 21 and still work correctly, though it would be less readable in this case.
int sum = 0; int number; int count = 30; while ( count >= 21 ) { cout << "Enter an integer:> "; cin >> number; sum = sum + number; count = count - 1; }In this particular program, as far as what we do with the count variable is concerned, all that really matters is that we somehow make the loop body execute exactly 10 times. Neither the endpoints nor the direction of counting matter, as long as we are consistent.
However, if the count variable were used for other purposes besides just controlling the number of times that the loop iterates, then both the exact values of the endpoints and the direction of counting could indeed matter. Whether these things matter depends on what the program is supposed to do.
When writing loops, a common programming mistake is the off-by-1 error, i.e. writing a loop so that it iterates either one more time or one less time than it should. To avoid or debug off-by-1 errors, check carefully the condition and initial values.
- Inputting a sequence of numbers on separate lines vs. inputting all the numbers on one line.
Run the program average1A.cpp and observe that it inputs the numbers each on a separate line, prompting for each number individually, as follows:This program averages a sequence of 10 integers entered interactively. Enter an integer:> 1 Enter an integer:> 2 Enter an integer:> 3 Enter an integer:> 4 Enter an integer:> 5 Enter an integer:> 6 Enter an integer:> 7 Enter an integer:> 8 Enter an integer:> 9 Enter an integer:> 0 The average is 4.5.On the other hand, compile and run average1B.cpp and observe that it inputs the numbers all on one line, prompting for all of them only once, as follows:
This program averages a sequence of 10 integers entered interactively. Enter the numbers:> 1 2 3 4 5 6 7 8 9 0 The average is 4.5.The loop in average1A.cpp, minus comments, is as follows:
int sum = 0; int number; int count = 0; while ( count < 10 ) { cout << "Enter an integer:> "; cin >> number; sum = sum + number; count = count + 1; }Note that prompting the user to enter a number is done inside the loop. Hence the repeated prompts.
On the other hand, the loop in average1B.cpp, minus comments, is as follows:
int sum = 0; int number; int count = 0; cout << "Enter the numbers:> "; while ( count < 10 ) { cin >> number; sum = sum + number; count = count + 1; }Note that this program prompts the user only once, before the loop.
- Named constants vs. multiple uses of a literal.
In average1B.cpp, observe that the number 10 is used in a total of four different places: (1) in the comment at the top (not really a part of the program itself, (2) in the main function's first statement, which outputs an introductory announcement to the user, (3) in the while loop condition, and (4) after the while loop, in the statement which computes the average by dividing the sum by 10.Suppose that, a month or two after writing this program, the programmer were to decide to revise it so that it now averages 12 numbers instead of 10 numbers. The programmer would need to remember to change the number 10 to 12 in all four places. If the programmer were to forget to change it in one place, the result might be a hard-to-debug error.
For this reason, it is best to avoid using a given literal more than once in a program. (Recall that a number hard-coded into a program is a numeric literal. We have also seen string literals, delimited by double quote marks, character literals, delimited by single quote marks.) It would be better to use the literal in only one place, so that, if and whenever its value needs to be changed, it will need to be changed in only one place, so we don't have to worry about forgetting to change it in a bunch of different places.
Instead of using a literal more than once in a program, we can define a named constant to be equal to the literal's value. Then, in all the places in the program where we would otherwise use the literal, we can use the constant instead.
For example, in average1C.cpp, the main function begins with the following statement:
const int NUMBER_OF_NUMBERS = 10;Then, in all parts of the program where we previously used the number 10, we use NUMBER_OF_NUMBERS instead. (We also got rid of the number 10 in the comment at the top, saying "a fixed number" instead.)
A constant is similar to a variable, except that a constant's value cannot be changed within the program. Constants are initialized in a manner similar to the way variables are initialized, except that the initialization statement for a constant must begin with the keyword const. Also, a constant must be initialized (assigned a value in the same statement that also declares its data type). Unlike a variable, a constant cannot be declared without being initialized.
- Count-controlled repetition with an endpoint decided at runtime.
Let us now consider a more flexible program which can average not just a hard-coded fixed number of numbers (e.g. 10 numbers), but any number of numbers, as decided by the user (not by the programmer) before entering the numbers. The following pseudocode first prompts the user to enter the number of numbers, before prompting the user to enter the numbers to be averaged:cout << "How many numbers do you want to average?> "; int numberOfNumbers; cin >> numberOfNumbers; int sum = 0; int number; cout << "Enter the numbers:> "; Do numberOfNumbers times: { cin >> number; sum = sum + number; } float average = (float) sum / numberOfNumbers;To write such a program at all, we need a loop. We cannot write the program by simply writing the following two statements over and over again, as we did in our first try at writing a program to average 10 numbers:
cin >> number; sum = sum + number;Because the number of numbers to be averaged is not known until the user says what it should be, we do not know, at the time we are writing the program, how many times these statements will need to be repeated.
Our pseudocode can be translated into the following C++ code, using a while loop:
cout << "How many numbers do you want to average?> "; int numberOfNumbers; cin >> numberOfNumbers; int sum = 0; int number; int count = 0; cout << "Enter the numbers:> "; while ( count < numberOfNumbers ) { cin >> number; sum = sum + number; count = count + 1; } float average = (float) sum / numberOfNumbers;For the complete program, see average1D.cpp.
Observe that the repetition in all our average1*.cpp programs, so far, is count-controlled, i.e. it ends when a count variable (i.e. a variable that is used to count repetitions) reaches a certain pre-determined endpoint value. The endpoint value of the count may either hard-coded into the program (as in average1A.cpp, average1B.cpp, and average1C.ppp) or determend at runtime (e.g. by the user, as in average1D.cpp), but, in either case, the endpoint value is decided before the loop itself begins executing.
(If the endpoint value were not decided before the loop begins executing, then the repetition would not be consdered to be "count-controlled. For example, the loops in our C-string processing programs do use count variables but are not count-controlled, because the final value of the count is not known before the loop begins. For example, it is not known, before the loop begins, at what index the null character will be found.)
- Arithmetic assignment operators and increment/decrement operators.
By now, you've seen plenty of assignments statements like the following:sum = sum + number; count = count + 1;These statements both change the value of a variable by adding a value to that variable. They can be abbreviated as follows:
sum += number; count += 1;The symbol += is one of five arithmetic assignment operators that can be used to abbreviate assignment statements, as follows:
Arithmetic
assignmentAssignment
a += b
a = a + b a -= b a = a - b a *= b a = a * b a /= b a = a / b a %= b a = a % bWe can further abbreviate statements which add or subtract the number 1, in particular. To that end, we can use the increment and decrement operators. For example, the statement
i = i + 1;can be replaced by either
i++;or
++i;Likewise, the statement
i = i - 1;can be replaced by either
i--;or
--i;In our program segment which averages a sequence of numbers entered by the user, the while loop can be re-written:
while ( i < numberOfNumbers ) { cin >> number; sum += number; count++; }For the complete program, see average1E.cpp.
The double plus sign ("++") is called the increment operator. The double minus sign ("--") is called the decrement operator. They can be used not just in headings of for loops, but in other places in our program, too.
In our examples so far, it does not matter whether the increment or decerment operator is placed to the left or the right of the variable. However, the position of the increment/dedrement operator relative to the variable does matter in a statement which consists of more than just the variable and the operator. For example, the following statement:
a = b / (i++);is equivalent to this sequence of two statements:
a = b / i; i = i + 1;whereas the following statement:
a = b / (++i);is equivalent to this sequence of two statements:
i = i + 1; a = b / i;When an increment is done inside a larger statement, an increment operator to the left of a variable causes the variable to be increased by one before the rest of the statement is executed, whereas an increment operator to the right of a variable causes the variable to be increased by one after the rest of the statement is executed.
And similarly with decrement operators. When an decrement is done inside a larger statement, a decrement operator to the left of a variable causes the variable to be decreased by one before the rest of the statement is executed, whereas a decrement operator to the right of a variable causes the variable to be decreased by one after the rest of the statement is executed.
Besides saving space in your source code file, the increment and decrement operators have another advantage over using an assignment satement to increment or decrement a variable. The increment and decrement operators are translated by the compiler into machine code statements that are more efficient, in their use of computer time, than the machine code translations of the equivalent assignment statements.
- Scope and duration of variables.
Look again at our our program segment which averages a sequence of integers entered by the user:cout << "How many numbers do you want to average?> "; int numberOfNumbers; cin >> numberOfNumbers; int sum = 0; int number; int count = 0; cout << "Enter the numbers:> "; while ( i < numberOfNumbers ) { cin >> number; sum += number; count++; } float average = (float) sum / numberOfNumbers;For the complete program, see average1E.cpp.
The variables number and sum are both declared before the loop and used within the loop. The variable sum is used after the loop as well as inside the loop, and, inside the loop, sum needs to remember its value from one iteration of the loop to the next. On the other hand, number is used only inside the loop, not anywhere else in the program, and it does NOT need to remember its value from one iteration of the loop to the next. Therefore, number can be declared inside the loop body:
cout << "How many numbers do you want to average?> "; int numberOfNumbers; cin >> numberOfNumbers; int sum = 0; int count = 0; cout << "Enter the numbers:> "; while ( i < numberOfNumbers ) { int number; cin >> number; sum += number; count++; } float average = (float) sum / numberOfNumbers;On the other hand, sum does need to be declared outside the loop body, because it needs to be able to remember its value from one iteration to the next.
For the complete revised program, see average1F.cpp.
A variable declared inside the loop body can be accessed only inside the loop body, whereas a variable declared before the loop body can be accessed both inside and outside the loop body.
More generally, a variable declared inside any block (a sequence of statements enclosed in curly braces) can be accessed only inside the block and ceases to exit after the block is finished executing. Such a variable refers to a memory location which is used only within the block and is deallocated (no longer set aside) when the block is finished executing.
The scope of a variable is the portion of your program in which the variable can be accessed. In our present example, the scope of a variable declared inside a loop body is the loop body.
The duration of a variable is how long it exists, i.e. how long the memory location continues to be set aside and can be referred to by the name of the variable. For the variables we have seen so far, their duration is the same as their scope, i.e. they begin to exist when they are declared, and then cease to exist at the end of the block in which they were declared.
If a variable is declared inside the body of a loop, it ceases to exist at the end of each iteration of the loop, then comes into existence again when the variable's declaration is reached again in the NEXT iteration in the loop. Thus, a variable declared inside a loop cannot be used to remember a value from one iteration to the next. If a variable needs to remember its value from one iteration of a while loop to the next, it must be declared before the beginning of the while loop.
According to most programming style guidelines today, it is considered best programming practice to declare all variables in the smallest scope possible. For example, if a variable is used only inside a loop and does not need to remember its value from one iteration of a loop to the next, it should be declared inside the loop.
- Avoiding division by zero.
Compile average1F.cpp, the averaging program we have been developing in this tutorial, and run it.Experiment with a variety of inputs. The program works fine if you enter a positive integer as the number of numbers to be averaged. But now try entering a negative number as the number of numbers to be averaged. The program's output will be (with the user input highlighted in boldface type):
This program averages a sequence of integers entered by the user. How many numbers do you want to average?> -1 The average is: -0.Now try entering zero as the number of numbers to be averaged. The program's output will be (with the user input highlighted in boldface type):
This program averages a sequence of integers entered by the user. How many numbers do you want to average?> 0 Floating exception (core dumped)This rather ugly, unfriendly complaint is about division by zero. Be sure to remove the core dump by typing:
rm coreWhen you write a program, you do not want the user to see such ugliness. So, if a program does division, you should write it so as to rule out the possibility of division by zero. In our averaging program, we can error-check0 the number entered by the user as the number of numbers to be averaged.
Compile average1G.cpp, a version of our program with error-checking, and run it. The value of numberOfNumbers is error-checked as follows:
if ( numberOfNumbers <= 0 ) { cout << "The number of numbers, " << numberOfNumbers << ", is invalid. Must be > 0." << endl; return 1; } // ifBecause of the return statement at the end of the if block, the rest of the program is not executed when the if condition is true, so a division by zero can never happen.
- Code traces with while loops.
On your forbin account, make sure that your present working directory (pwd) is your hw03 directory, inside your homework directory. (Change directories as necessary.) Then copy into it LineNumberer.class, as follows:cp ~nixon/java/LineNumberer.class .Then use it to generate a line-numbered copy of average1G.cpp, as follows:java LineNumberer average1G.cpp 2thereby generating the file average1G.cpp.txt, a line-numbered copy of average1G.cpp.
Download the file average1G.cpp.txt, print it out, and compare it with these sample code traces.
Back to: