Our next example uses arrays to summarize data collected in a survey. Consider the following problem statement:
Twenty students were asked to rate on a scale of 1 to 5 the quality of the food in the student cafeteria, with 1 being “awful” and 5 being “excellent.” Place the 20 responses in an integer array and determine the frequency of each rating.
This is a typical array-processing app (Fig. 8.9). We wish to summarize the number of responses of each type (that is, 1–5). Array responses
(lines 10–11) is a 20-element integer array containing the students’ survey responses. The last value in the array is intentionally an incorrect response (14
). When a C# program executes, the runtime checks array element indices for validity—all indices must be greater than or equal to 0 and less than the length of the array. Any attempt to access an element outside that range of indices results in a runtime error known as an IndexOutOfRangeException
. At the end of this section, we’ll discuss the invalid response, demonstrate array bounds checking and introduce C#’s exception-handling mechanism, which can be used to detect and handle an Index-OutOfRangeException
.
frequency
ArrayWe use the six-element array frequency
(line 12) to count the number of occurrences of each response. Each element is used as a counter for one of the possible types of survey responses—frequency[1]
counts the number of students who rated the food as 1, frequency[2]
counts the number of students who rated the food as 2, and so on.
Lines 16–28 read the responses from the array responses
one at a time and increments on of the counters frequency[1]
to frequency[5]
; we ignore frequency[0]
because the survey responses are limited to the range 1–5. The key statement in the loop appears in line 20. This statement increments the appropriate frequency
counter as determined by the value of responses[answer]
.
Let’s step through the first few iterations of the foreach
statement:
When the counter answer
is 0
, responses[answer]
is the value of responses[0]
(that is, 1
—see line 10). In this case, frequency[responses[answer]]
is interpreted as frequency[1]
, and the counter frequency[1]
is incremented by one. To evaluate the expression, we begin with the value in the innermost set of brackets (answer
, currently 0
). The value of answer
is plugged into the expression, and the next set of brackets (responses[answer]
) is evaluated. That value is used as the index for the frequency
array to determine which counter to increment (in this case, frequency[1]
).
The next time through the loop answer
is 1
, responses[answer]
is the value of responses[1]
(that is, 2
—see line 10), so frequency[responses[answer]]
is interpreted as frequency[2]
, causing frequency[2]
to be incremented.
When answer
is 2
, responses[answer]
is the value of responses[2]
(that is, 5
—see line 10), so frequency[responses[answer]]
is interpreted as frequency[5]
, causing frequency[5]
to be incremented, and so on.
Regardless of the number of responses processed in the survey, only a six-element array (in which we ignore element zero) is required to summarize the results, because all the correct response values are between 1 and 5, and the index values for a six-element array are 0–5. In the output in Fig. 8.9, the frequency column summarizes only 19 of the 20 values in the responses
array—the last element of the array responses
contains an incorrect response that was not counted. Lines 16–28 could be simplified, by changing line 16 to
foreach (var response in responses)
line 20 to
++frequency[response];
and modifying the error message displayed by lines 25–26.
An exception indicates a problem that occurs while a program executes. Exception handling enables you to create fault-tolerant programs that can resolve (or handle) exceptions. In many cases, this allows a program to continue executing as if no problems were encountered. For example, the Student Poll app still displays results (Fig. 8.9), even though one of the responses was out of range. More severe problems might prevent a program from continuing normal execution, instead requiring the program to notify the user of the problem, then terminate. When the runtime or a method detects a problem, such as an invalid array index or an invalid method argument, it throws an exception—that is, an exception occurs. The exception here is thrown by the runtime. In Section 10.2, you’ll see how to throw your own exceptions.
try
StatementTo handle an exception, place any code that might throw an exception in a try
statement (Fig. 8.9, lines 18–27). The try
block (lines 18–21) contains the code that might throw an exception, and the catch
block (lines 22–27) contains the code that handles the exception if one occurs. You can have many catch
blocks to handle different types of exceptions that might be thrown in the corresponding try
block. When line 20 correctly increments an element of the frequency
array, lines 22–27 are ignored. The braces that delimit the bodies of the try
and catch
blocks are required.
catch
BlockWhen the program encounters the value 14
in the responses
array, it attempts to add 1
to frequency[14]
, which does not exist—the frequency
array has only six elements. Because the runtime performs array bounds checking, it generates an exception—specifically line 20 throws an IndexOutOfRangeException
to notify the program of this problem. At this point the try
block terminates and the catch
block begins executing—if you declared any variables in the try
block, they no longer exist, so they’re not accessible in the catch
block.
The catch
block declares an exception parameter’s type (IndexOutOfRangeException
) and name (ex
). The catch
block can handle exceptions of the specified type. Inside the catch
block, you can use the parameter’s identifier to interact with a caught exception object.
When writing code to access an array element, ensure that the array index remains greater than or equal to 0 and less than the length of the array. This will help prevent Index-OutOfRangeExceptions
in your program.
Message
Property of the Exception ParameterWhen lines 22–27 catch the exception, the program displays a message indicating the problem that occurred. Line 24 uses the exception object’s built-in Message
property to get the error message and display it. Once the message is displayed, the exception is considered handled and the program continues with the next statement after the catch
block’s closing brace. In this example, the end of the foreach
statement is reached (line 28), so the program continues with the next iteration of the loop. We use exception handling again in Chapter 10, then Chapter 13 presents a deeper look at exception handling.