Chapter 5
IN THIS CHAPTER
Making decisions if
you can
Deciding what else
to do
Using the while
and do … while
loops
Using the for
loop and understanding scope
Consider this simple program:
using System;
namespace HelloWorld
{
public class Program
{
// This is where the program starts.
static void Main(string[] args)
{
// Prompt user to enter a name.
Console.WriteLine("Enter your name, please:");
// Now read the name entered.
string name = Console.ReadLine();
// Greet the user with the entered name.
Console.WriteLine("Hello, " + name);
// Wait for user to acknowledge the results.
Console.WriteLine("Press Enter to terminate … ");
Console.Read();
}
}
}
Beyond introducing you to a few fundamentals of C# programming, this program is almost worthless. It simply spits back out whatever you entered. You can imagine more complicated program examples that accept input, perform some type of calculations, generate some type of output (otherwise, why do the calculations?), and then exit at the bottom. However, a program such as this one can be of only limited use.
One key element of any computer processor is its ability to make decisions, which means that the processor sends the flow of execution down one path of instructions if a condition is true or down another path if the condition is false (not true). Any programming language must offer this fundamental capability to control the flow of execution.
The three basic types of flow control are the if
statement, the loop, and the jump. (Chapter 6 of this minibook describes the foreach
looping control.)
The basis of all C# decision-making capability is the if
statement:
if (bool-expression)
{
// Control goes here if the expression is true.
}
// Control passes to this statement whether the expression is true or not.
A pair of parentheses immediately following the keyword if
contains a conditional expression of type bool
. (See Chapter 2 of this minibook for a discussion of bool
expressions.) Immediately following the expression is a block of code set off by a pair of braces. If the expression is true, the program executes the code within the braces; if the expression is not true, the program skips the code in the braces. (If the program executes the code in braces, it ends just after the closing brace and continues from there.) The if
statement is easier to understand by looking at a concrete example:
// Make sure that a is positive:
// If a is less than 1 …
if (a < 1)
{
// … then assign 1 to it so that it's positive.
a = 1;
}
This segment of code ensures that the variable a
is non-negative — greater than or equal to 1. The if
statement says, “If a
is less than 1, assign 1 to a
.” (In other words, turn a
into a positive value.)
Consider a small program that calculates interest. The user enters the principal amount and the interest rate, and the program spits out the resulting value for each year. (This program isn’t sophisticated.) The simplistic calculation appears as follows in C#:
// Calculate the value of the principal plus interest.
decimal interestPaid;
interestPaid = principal * (interest / 100);
// Now calculate the total.
decimal total = principal + interestPaid;
The first equation multiplies the principal principal
times the interest interest
to produce the interest to be paid — interestPaid
. (You divide by 100
because interest is usually calculated by entering a percentage amount.) The interest to be paid is then added back into the principal, resulting in a new principal, which is stored in the variable total
.
The program must anticipate almost anything when dealing with human input. For example, you don't want your program to accept a negative principal or interest amount (well, maybe a negative interest). The following CalculateInterest
program includes checks to ensure that neither of these entries happens:
static void Main(string[] args)
{
// Prompt user to enter source principal.
Console.Write("Enter principal: ");
string principalInput = Console.ReadLine();
decimal principal = Convert.ToDecimal(principalInput);
// Make sure that the principal is not negative.
if (principal < 0)
{
Console.WriteLine("Principal cannot be negative");
principal = 0;
}
// Enter the interest rate.
Console.Write("Enter interest: ");
string interestInput = Console.ReadLine();
decimal interest = Convert.ToDecimal(interestInput);
// Make sure that the interest is not negative either.
if (interest < 0)
{
Console.WriteLine("Interest cannot be negative");
interest = 0;
}
// Calculate the value of the principal plus interest.
decimal interestPaid = principal * (interest / 100);
// Now calculate the total.
decimal total = principal + interestPaid;
// Output the result.
Console.WriteLine(); // Skip a line.
Console.WriteLine("Principal = " + principal);
Console.WriteLine("Interest = " + interest + "%");
Console.WriteLine();
Console.WriteLine("Interest paid = " + interestPaid);
Console.WriteLine("Total = " + total);
Console.Read();
}
The sample program uses the ReadLine()
command to read in whatever the user types; the program returns the value entered, in the form of a string
, when the user presses Enter. Because the program is looking for the principal in the form of a decimal
, the input string
must be converted using the Convert.ToDecimal()
command. The result is stored in principalInput
.
The next line in the example checks principal
. If it’s negative, the program outputs a polite message indicating that the input is invalid. The program does the same thing for the interest rate, and then it performs the simplistic interest calculation outlined earlier, in the “Introducing the if statement” section, and spits out the result, using a series of WriteLine()
commands. Here's some example output from the program:
Enter principal: 1234
Enter interest: 21
Principal = 1234
Interest = 21%
Interest paid = 259.14
Total = 1493.14
Executing the program with illegal input generates the following output:
Enter principal: 1234
Enter interest: -12.5
Interest cannot be negative
Principal = 1234
Interest = 0%
Interest paid = 0
Total = 1234
Sometimes, your code must check for mutually exclusive conditions. For example, the following code segment stores the maximum of two numbers, a
and b
, in the variable max
:
// Store the maximum of a and b into the variable max.
int max;
// If a is greater than b …
if (a > b)
{
// … save a as the maximum.
max = a;
}
// If a is less than or equal to b …
if (a <= b)
{
// … save b as the maximum.
max = b;
}
The second if
statement causes needless processing because the two conditions are mutually exclusive. If a
is greater than b
, a
can't possibly be less than or equal to b
. C# defines an else
statement for just this case. The else
keyword defines a block of code that's executed when the if
block isn’t. The code segment to calculate the maximum now appears this way:
// Store the maximum of a and b into the variable max.
int max;
// If a is greater than b …
if (a > b)
{
// … save a as the maximum; otherwise …
max = a;
}
else
{
// … save b as the maximum.
max = b;
}
If a
is greater than b
, the first block is executed; otherwise, the second block is executed. In the end, max
contains the greater of a
or b
.
Sequences of else
clauses can become confusing. Some programmers like to avoid them when doing so doesn't cause even more confusion. You could write the maximum calculation like this:
// Store the maximum of a and b into the variable max.
int max;
// Start by assuming that a is greater than b.
max = a;
// If it is not …
if (b > a)
{
// … then you can change your mind.
max = b;
}
bool informal = true;
string name = informal ? "Chuck" : "Charles"; // Returns "Chuck"
This chunk evaluates the expression before the colon. If the expression is true, return the value after the colon but before the question mark. If the expression is false, return the value after the question mark. This process turns an if…else
into an expression. Best practice advises using ternary only rarely because it truly is cryptic.
int x = 2;
Console.WriteLine(x == 1 ? 1 : "Hello");
When x is equal to 1, the output of this conditional expression is the value 1. When x isn’t equal to 1, the output of this conditional expression is the string "Hello"
. There are all sorts of ways in which to use this new typed conditional expression, including within switch
statements. You can discover more about them at https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/target-typed-conditional-expression
.
The CalculateInterest
program warns the user of illegal input; however, continuing with the interest calculation, even if one of the values is illogical, doesn't seem quite right. It causes no real harm here because the interest calculation takes little or no time and the user can ignore the results, but some calculations aren’t nearly as quick. In addition, why ask the user for an interest rate after entering an invalid value for the principal? The user knows that the results of the calculation will be invalid. (You’d be amazed at how much it infuriates users to require input after they know the calculation will fail.) The program should ask the user for an interest rate only if the principal is reasonable and perform the interest calculation only if both values are valid. To accomplish this, you need two if
statements, one within the other.
static void Main(string[] args)
{
// Define a maximum interest rate.
int maximumInterest = 50;
// Prompt user to enter source principal.
Console.Write("Enter principal: ");
string principalInput = Console.ReadLine();
decimal principal = Convert.ToDecimal(principalInput);
// If the principal is negative …
if (principal < 0)
{
// … generate an error message …
Console.WriteLine("Principal cannot be negative");
}
else // Go here only if principal was > 0: thus valid.
{
// … otherwise, enter the interest rate.
Console.Write("Enter interest: ");
string interestInput = Console.ReadLine();
decimal interest = Convert.ToDecimal(interestInput);
// If the interest is negative or too large …
if (interest < 0 || interest > maximumInterest)
{
// … generate an error message as well.
Console.WriteLine("Interest cannot be negative " +
"or greater than " + maximumInterest);
interest = 0;
}
else // Reach this point only if all is well.
{
// Both the principal and the interest appear to be legal;
// calculate the value of the principal plus interest.
decimal interestPaid;
interestPaid = principal * (interest / 100);
// Now calculate the total.
decimal total = principal + interestPaid;
// Output the result.
Console.WriteLine(); // Skip a line.
Console.WriteLine("Principal = " + principal);
Console.WriteLine("Interest = " + interest + "%");
Console.WriteLine();
Console.WriteLine("Interest paid = " + interestPaid);
Console.WriteLine("Total = " + total);
}
}
Console.Read();
}
The program first reads the principal from the user. If the principal is negative, the program outputs an error message and quits. If the principal is not negative, control passes to the else
clause, where the program continues executing.
The interest rate test has been improved in this example. Here, the program requires an interest rate that's non-negative (a mathematical law) and less than a maximum rate (a judiciary law). This if
statement uses the following compound test:
if (interest < 0 || interest > maximumInterest)
This statement is true if interest
is less than 0 or greater than maximumInterest
. Notice the code declares maximumInterest
as a variable at the top of the program rather than hard-code it here. Hard-coding refers to using values directly in your code rather than creating a variable to hold them.
Enter principal: 1234
Enter interest: -12.5
Interest cannot be negative or greater than 50.
Only when the user enters both a legal principal and a legal interest rate does the program generate the correct calculation:
Enter principal: 1234
Enter interest: 12.5
Principal = 1234
Interest = 12.5%
Interest paid = 154.250
Total = 1388.250
You often want to test a variable for numerous different values. For example, maritalStatus
may be 0 for unmarried, 1 for married, 2 for divorced, 3 for widowed, or 4 for none of your business. To differentiate among these values, you could use the following series of if
statements:
if (maritalStatus == 0)
{
// Must be unmarried …
// … do something …
}
else
{
if (maritalStatus == 1)
{
// Must be married …
// … do something else …
You can see that these repetitive if
statements grow tiresome quickly. Testing for multiple cases is such a common occurrence that C# provides a special construct to decide between a set of mutually exclusive conditions. This control, the switch
, works as follows:
switch (maritalStatus)
{
case 0:
// … do the unmarried stuff …
break;
case 1:
// … do the married stuff …
break;
case 2:
// … do the divorced stuff …
break;
case 3:
// … do the widowed stuff …
break;
case 4:
// … get out of my face …
break;
default:
// Goes here if it fails to pass a case;
// this is probably an error condition.
break;
}
The expression at the top of the switch
statement is evaluated. In this case, the expression is simply the variable maritalStatus
. The value of that expression is then compared against the value of each of the cases. Control passes to the default
clause if no match is found. The argument to the switch
statement can also be a string
:
string s = "Davis";
switch(s)
{
case "Davis":
// … control will actually pass here …
break;
case "Smith":
// … do Smith stuff …
break;
case "Jones":
// … do Jones stuff …
break;
case "Hvidsten":
// … do Hvidsten stuff …
break;
default:
// Goes here if it doesn't pass any cases.
break;
}
switch()
must be one of the counting types (including char
) or a string
when using older versions of C#. Starting with C# 7.0, you can use any non-null value.case
values must refer to values of the same type as the switch
expression.case
values must be constant in the sense that their value must be known at compile time. (A statement such as case x
isn't legal unless x
is a type of constant.)Each clause must end in a break
statement (or another exit command, such as return
). The break
statement passes control out of the switch
.
You can omit a break statement if two cases lead to the same actions: A single case
clause may have more than one case
label, as in this example:
string s = "Davis";
switch(s)
{
case "Davis":
case "Hvidsten":
// Do the same thing whether s is Davis or Hvidsten
// since they're related.
break;
case "Smith":
// … do Smith stuff …
break;
default:
// Goes here if it doesn't pass any cases.
break;
}
This approach enables the program to perform the same operation, whether the input is Davis or Hvidsten.
Starting with C# 8.0 and above, you can use a new type of switch
called a switch expression. This kind of switch
allows you to use expressions as part of a switch
statement. An expression is a construction that consists of operators and operands. For example, x > y
is an expression. The best way to understand switch expressions is to see one in action, as shown in the SwitchExpression
example.
public enum Greetings
{
Morning,
Afternoon,
Evening,
Night
}
public static string GreetString(Greetings value) => value switch
{
Greetings.Morning => "Good Morning!",
Greetings.Afternoon => "Good Afternoon!",
Greetings.Evening => "See you tomorrow!",
Greetings.Night => "Are you still here?",
// Added solely to cover all cases.
_ => "Not sure what time it is!"
};
static void Main(string[] args)
{
Console.WriteLine(GreetString(Greetings.Morning));
Console.WriteLine(GreetString(Greetings.Afternoon));
Console.WriteLine(GreetString(Greetings.Evening));
Console.WriteLine(GreetString(Greetings.Night));
Console.ReadLine();
}
The example begins by creating the Greetings enum
(or enumeration). An enumeration is simply a list of value names you want to use. Don't worry about enumerations too much now because you see them demonstrated in Chapter 10 of this minibook. In this case, the enumeration specifies the kinds of greetings that someone can use.
The switch
expression comes next. It works similarly to a regular switch
in that you start with a variable, value
, that you compare to a series of cases. The difference is that value
is of type Greetings
in this case. When a particular Greetings
value matches, the switch
expression outputs a string
.
Testing the switch
expression comes next. The code in Main()
tests every combination of Greetings. You see this output:
Good Morning!
Good Afternoon!
See you tomorrow!
Are you still here?
<PropertyGroup>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
C# 9.0 made it possible to extend the switch
expression even further by using pattern matching. A pattern can be just about anything that you can recognize as representing a group of related values, even if the values aren’t necessarily contiguous or of the same type. For example, a telephone number is a pattern because you recognize its structure. The SwitchPattern
example uses an easier to recognize pattern, those of letters, numbers, and special characters.
public static string LetterType(char letter) => letter switch
{
>= 'a' and <= 'z' => "lowercase letter",
>= 'A' and <= 'Z' => "uppercase letter",
>= '1' and <= '9' => "number",
>= ' ' and <= '/' or
>= ':' and <= '@' or
>= '[' and <= '`' or
>= '{' and <= '~' => "special character",
_ => "Unknown letter type"
};
static void Main(string[] args)
{
Console.WriteLine("a is a " + LetterType('a') + ".");
Console.WriteLine("B is an " + LetterType('B') + ".");
Console.WriteLine("3 is a " + LetterType('3') + ".");
Console.WriteLine("? is a " + LetterType('?') + ".");
Console.WriteLine("À is a " + LetterType('À') + ".");
Console.ReadLine();
}
In this case, the switch
uses logical patterns to define letter types based on the content of an input. Notice how you can combine and
and or
values to create the pattern. The final entry provides a default response in case the input character isn't recognized as part of the pattern. You can see more pattern types supported by C# at https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns
.
The testing coding in Main()
goes through all the various expected character types. It then provides an uppercase A with a grave accent as input, which isn't part of the pattern. Here’s the output from the example.
a is a lowercase letter.
B is an uppercase letter.
3 is a number.
? is a special character.
A is an Unknown letter type.
<PropertyGroup>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
The if
statement enables a program to take different paths through the code being executed, depending on the results of a bool
expression. This statement provides for drastically more interesting programs than programs without decision-making capability. Adding the ability to execute a set of instructions repeatedly adds another quantum jump in capability.
Consider the CalculateInterest
program from the section “Introducing the if statement,” earlier in this chapter. Performing this simple interest calculation by using a calculator (or by hand, using a piece of paper) would be much easier than writing and executing a program.
If you could calculate the amount of principal for each of several succeeding years, that would be even more useful. What you need is a way for the computer to execute the same short sequence of instructions multiple times — known as a loop.
The C# keyword while
introduces the most basic form of execution loop:
while (bool-expression)
{
// … repeatedly executed as long as the expression is true.
}
When the while
loop is first encountered, the bool
expression is evaluated. If the expression is true, the code within the block is executed. When the block of code reaches the closed brace, control returns to the top, and the whole process starts over again. Control passes beyond the closed brace the first time the bool
expression is evaluated and turns out to be false.
You can use the while
loop to create the CalculateInterestTable
program, a looping version of the CalculateInterest
program. CalculateInterestTable
calculates a table of principals showing accumulated annual payments:
static void Main(string[] args)
{
// Define a maximum interest rate.
int maximumInterest = 50;
// Prompt user to enter source principal.
Console.Write("Enter principal: ");
string principalInput = Console.ReadLine();
decimal principal = Convert.ToDecimal(principalInput);
// If the principal is negative …
if (principal < 0)
{
// … generate an error message …
Console.WriteLine("Principal cannot be negative");
}
else // Go here only if principal was > 0: thus valid.
{
// … otherwise, enter the interest rate.
Console.Write("Enter interest: ");
string interestInput = Console.ReadLine();
decimal interest = Convert.ToDecimal(interestInput);
// If the interest is negative or too large …
if (interest < 0 || interest > maximumInterest)
{
// … generate an error message as well.
Console.WriteLine("Interest cannot be negative " +
"or greater than " + maximumInterest);
interest = 0;
}
else // Reach this point only if all is well.
{
// Both the principal and the interest appear to be
// legal; finally, input the number of years.
Console.Write("Enter number of years: ");
string durationInput = Console.ReadLine();
int duration = Convert.ToInt32(durationInput);
// Verify the input.
Console.WriteLine(); // Skip a line.
Console.WriteLine("Principal = " + principal);
Console.WriteLine("Interest = " + interest + "%");
Console.WriteLine("Duration = " + duration + " years");
Console.WriteLine();
// Now loop through the specified number of years.
int year = 1;
while (year <= duration)
{
// Calculate the value of the principal plus interest.
decimal interestPaid;
interestPaid = principal * (interest / 100);
// Now calculate the new principal by adding
// the interest to the previous principal amount.
principal = principal + interestPaid;
// Round off the principal to the nearest cent.
principal = decimal.Round(principal, 2);
// Output the result.
Console.WriteLine(year + "-" + principal);
// Skip over to next year.
year = year + 1;
}
}
}
Console.Read();
}
The output from a trial run of CalculateInterestTable
appears this way:
Enter principal: 10000
Enter interest: 5.5
Enter number of years: 5
Principal = 10000
Interest = 5.5%
Duration = 5 years
1-10550.00
2-11130.25
3-11742.41
4-12388.24
5-13069.59
Each value represents the total principal after the number of years elapsed, assuming simple interest compounded annually. For example, the value of $10,000 at 5.5 percent is $13,069.59 after five years.
The CalculateInterestTable
program begins by reading the principal and interest values from the user and checking to make sure that they're valid. CalculateInterestTable
then reads the number of years over which to iterate and stores this value in the variable duration
.
Before entering the while
loop, the program declares a variable year
, which it initializes to 1
. This will be the “current year” — that is, this number changes “each year” as the program loops. If the year number contained in year
is less than the total duration contained in duration
, the principal for “this year” is recalculated by calculating the interest based on the “previous year.” The calculated principal is output along with the current-year offset.
The key to the program lies in the last line within the block. The statement year = year + 1;
increments year
by 1. If year
begins with the value 3
, its value will be 4
after this expression. This incrementing moves the calculations along from one year to the next.
After the year has been incremented, control returns to the top of the loop, where the value year
is compared to the requested duration. In the sample run, if the current year is less than 5, the calculation continues. After being incremented five times, the value of year
becomes 6, which is greater than 5, and program control passes to the first statement after the while
loop — the program stops looping.
The counting variable year
in CalculateInterestTable
must be declared and initialized before the while
loop in which it is used. In addition, the year
variable must be incremented, usually as the last statement within the loop. As this example demonstrates, you have to look ahead to see which variables you need. This pattern is easier to use after you've written a few thousand while
loops.
int nYear = 1;
while (nYear < 10)
{
// … whatever …
}
This example doesn’t increment nYear
. Without the increment, nYear
is always 1
and the program loops forever. The only way to exit this infinite loop is to terminate the program by pressing Ctrl+C. (So nothing is truly infinite, with the possible exception of a particle passing through the event horizon of a black hole.)
A variation of the while
loop is the do … while
loop. In this example, the condition isn't checked until the end of the loop:
int year = 1;
do
{
// … some calculation …
year = year + 1;
} while (year < duration);
In contrast to the while
loop, the do … while
loop is executed at least once, regardless of the value of duration
.
You can use two special commands to change how a loop executes: break
and continue
. Executing the break
statement causes control to pass to the first expression immediately following the loop. The similar continue
statement passes control straight back up to the conditional expression at the top of the loop to start over and get it right this time.
Suppose that you want to take your money out of the bank as soon as the principal exceeds a certain number of times the original amount, irrespective of the duration in years. You could easily accommodate this amount by adding the following code (in bold) within the loop:
// Now loop through the specified number of years.
int year = 1;
while (year <= duration)
{
// Calculate the value of the principal plus interest.
decimal interestPaid;
interestPaid = principal * (interest / 100);
// Now calculate the new principal by adding
// the interest to the previous principal amount.
principal = principal + interestPaid;
// Round off the principal to the nearest cent.
principal = decimal.Round(principal, 2);
// Output the result.
Console.WriteLine(year + "-" + principal);
// Skip over to next year.
year = year + 1;
// Determine whether we have reached our goal.
if (principal > (maxPower * originalPrincipal))
{
break;
}
}
The break
statement isn't executed until the condition within the if
comparison is true — in this case, until the calculated principal is maxPower
times the original principal or more. Executing the break
statement passes control outside the while(year <= duration)
statement, and the program resumes execution immediately after the loop.
The CalculateInterestTable
program is smart enough to terminate in the event that the user enters an invalid balance or interest amount. However, jumping immediately out of the program just because the user mistypes something seems harsh. A combination of while
and break
enables the program to be a little more flexible. The CalculateInterestTableMoreForgiving
program demonstrates the principle this way:
static void Main(string[] args)
{
// Define a maximum interest rate.
int maximumInterest = 50;
// Prompt user to enter source principal; keep prompting
// until the correct value is entered.
decimal principal;
while (true)
{
Console.Write("Enter principal: ");
string principalInput = Console.ReadLine();
principal = Convert.ToDecimal(principalInput);
// Exit if the value entered is correct.
if (principal >= 0)
{
break;
}
// Generate an error on incorrect input.
Console.WriteLine("Principal cannot be negative");
Console.WriteLine("Try again");
Console.WriteLine();
}
// Now enter the interest rate.
decimal interest;
while (true)
{
Console.Write("Enter interest: ");
string interestInput = Console.ReadLine();
interest = Convert.ToDecimal(interestInput);
// Don't accept interest that is negative or too large …
if (interest >= 0 && interest <= maximumInterest)
{
break;
}
// … generate an error message as well.
Console.WriteLine("Interest cannot be negative " +
"or greater than " + maximumInterest);
Console.WriteLine("Try again");
Console.WriteLine();
}
// Both the principal and the interest appear to be
// legal; finally, input the number of years.
Console.Write("Enter number of years: ");
string durationInput = Console.ReadLine();
int duration = Convert.ToInt32(durationInput);
// Verify the input.
Console.WriteLine(); // Skip a line.
Console.WriteLine("Principal = " + principal);
Console.WriteLine("Interest = " + interest + "%");
Console.WriteLine("Duration = " + duration + " years");
Console.WriteLine();
// Now loop through the specified number of years.
int year = 1;
while (year <= duration)
{
// Calculate the value of the principal plus interest.
decimal interestPaid;
interestPaid = principal * (interest / 100);
// Now calculate the new principal by adding
// the interest to the previous principal.
principal = principal + interestPaid;
// Round off the principal to the nearest cent.
principal = decimal.Round(principal, 2);
// Output the result.
Console.WriteLine(year + "-" + principal);
// Skip over to next year.
year = year + 1;
}
Console.Read();
}
This program works largely the same way as do the examples in previous sections of this chapter, except in the area of user input. This time, a while
loop replaces the if
statement used in earlier examples to detect invalid input (you would use the same sort of loop to obtain the number of years, but it has been omitted to save space):
decimal principal;
while (true)
{
Console.Write("Enter principal: ");
string principalInput = Console.ReadLine();
principal = Convert.ToDecimal(principalInput);
// Exit when the value entered is correct.
if (principal >= 0)
{
break;
}
// Generate an error on incorrect input.
Console.WriteLine("Principal cannot be negative");
Console.WriteLine("Try again");
Console.WriteLine();
}
This section of code inputs a value from the user within a loop. If the value of the text is okay, the program exits the input loop and continues. However, if the input has an error, the user sees an error message and control passes back to the program flow to start over.
Notice that the conditionals have been reversed because the question is no longer whether illegal input should generate an error message, but rather whether the correct input should exit the loop. In the interest section, for example, consider this test:
principal < 0 || principal > maximumInterest
This test changes to this:
interest >= 0 && interest <= maximumInterest
Clearly, interest >= 0
is the opposite of interest < 0
. What may not be as obvious is that the OR (||
) operator is replaced with an AND (&&
) operator. It says, “Exit the loop if the interest is greater than zero AND less than the maximum amount (in other words, if it is correct).” Note that the principal
variable must be declared outside the loop because of scope rules, which is explained in the next section.
Enter principal: -1000
Principal cannot be negative
Try again
Enter principal: 1000
Enter interest: -10
Interest cannot be negative or greater than 50
Try again
Enter interest: 10
Enter number of years: 5
Principal = 1000
Interest = 10%
Duration = 5 years
1-1100.0
2-1210.00
3-1331.00
4-1464.10
5-1610.51
Press Enter to terminate …
The program refuses to accept a negative principal or interest amount and patiently explains the mistake on each loop. However, you'd still need to add code to handle situations in which the user entered a blank input or a string value, such as seven.
A variable declared within the body of a loop is defined only within that loop. Consider this code snippet:
int days = 1;
while (days < duration)
{
int average = value / days;
// … some series of commands …
days = days + 1;
}
The while
loop is the simplest and second most commonly used looping structure in C#. Compared to the for
loop, however, the while
loop is used about as often as metric tools in an American machine shop. The for
loop has this structure:
for (initExpression; condition; incrementExpression)
{
// … body of code …
}
When the for
loop is encountered, the program first executes the initExpression
expression and then tests the condition
. If the condition
expression is true, the program executes the body of the loop, which is surrounded by the braces immediately following the for
command. When the program reaches the closed brace, control passes to incrementExpression
and then back to condition
, where the next pass through the loop begins. In fact, the definition of a for
loop can be converted into this while
loop:
initExpression;
while(condition)
{
// … body of code …
incrementExpression;
}
You can better see how the for
loop works in this example:
// Here is one C# expression or another.
a = 1;
// Now loop for awhile.
for (int year = 1; year <= duration; year = year + 1)
{
// … body of code …
}
// The program continues here.
a = 2;
Assume that the program has just executed the a = 1;
expression. Next, the program declares the variable year
and initializes it to 1
. Then the program compares year
to duration
. If year
is less than duration
, the body of code within the braces is executed. After encountering the closed brace, the program jumps back to the top and executes the year = year + 1
clause before sliding back over to the year < duration
comparison.
Why do you need the for
loop if C# has an equivalent while
loop? The short answer is that you don't — the for
loop doesn’t bring anything to the table that the while
loop can't already do.
However, the sections of the for
loop exist for convenience — and to clearly establish the three parts that every loop should have: the setup, exit criteria, and increment. Not only is this arrangement easier to read, it’s also easier to get right. (Remember that the most common mistakes in a while
loop are forgetting to increment the counting variable and failing to provide the proper exit criteria.) The most important reason to understand the for
loop is that it's the loop everyone uses — and it (along with its cousin, foreach
) is the one you see 90 percent of the time when you’re reading other people’s code.
The increment operator is particularly popular when writing for
loops. (Chapter 4 of this minibook describes the increment operator along with other operators.) The previous for
loop is usually written this way:
for (int year = 1; year <= nDuration; year++)
{
// … body of code …
}
The for
loop has one variation that you may find hard to understand. If the logical condition expression is missing, it’s assumed to be true
. Thus for (;;)
is an infinite loop. You see for (;;)
used as an infinite loop more often than while (true)
.
An inner loop can appear within an outer loop, this way:
for ( …some condition …)
{
for ( …some other condition …)
{
// … do whatever …
}
}
The inner loop is executed to completion during each pass through the outer loop. The loop variable (such as year
) used in the inner for
loop isn't defined outside the inner loop’s scope.
do // Start a do..while loop.
{
for( …) // Start some for loop.
{
} while( …) // End do..while loop.
} // End for loop.
// for loop A
for( …some condition …)
{
// for loop B
for( …some other condition …)
{
// … do whatever …
if (something is true)
{
break; // Breaks out of loop B and not loop A
}
}
}
C# doesn't have a break
statement that exits both loops simultaneously. You must use two separate break
statements, one for each loop.
3.145.193.134