🎮 Advanced Control Flow in C#
Having mastered basic decisions (if-else
), multiple choices (switch
), and fundamental loops (while
, do-while
) in the previous lessons, we now delve into more advanced techniques and considerations for controlling program execution flow in C#.
This lesson covers:
- Fine-tuning loop behavior with
break
andcontinue
. - Understanding the scope and impact of
return
within loops and methods. - Briefly introducing the
for
loop (a common loop structure not explicitly detailed in the source notes but essential for C#). - Nested control structures.
- (Mention) Advanced
switch
features like pattern matching (though detailed implementation might be beyond initial notes).
(Prerequisites: Ensure you understand the concepts from “Control Flow - Beginner” and “Intermediate”.)
Lesson: Precise Control and Structure
Mastering Loop Control: break
and continue
While loops execute based on their condition, sometimes you need finer control within the loop’s execution.
break
: As seen inswitch
statements,break
can also be used inside loops (while
,do-while
,for
,foreach
). When encountered, it immediately terminates the innermost loop it resides in. Execution continues with the first statement after the terminated loop.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// Example: Find the first multiple of 7 int number = 1; while (true) // Potentially infinite loop! { if (number % 7 == 0) { Console.WriteLine($"Found first multiple of 7: {number}"); break; // Exit the while loop } number++; if (number > 100) // Safety break to prevent actual infinite loop { Console.WriteLine("Reached limit without finding multiple."); break; } } // Execution continues here after break Console.WriteLine("Loop finished.");
continue
: This statement doesn’t exit the loop entirely. Instead, it skips the rest of the current iteration and jumps directly to the loop’s condition check (forwhile
,do-while
) or the update step (forfor
loops) to start the next iteration.1 2 3 4 5 6 7 8 9 10 11 12
// Example: Print only odd numbers up to 10 int i = 0; while (i < 10) { i++; if (i % 2 == 0) // Is 'i' even? { continue; // Skip the Console.WriteLine for even numbers } // This line is skipped if 'continue' was executed Console.WriteLine($"Odd number: {i}"); }
break
and continue
provide powerful ways to handle special cases or exit conditions within loops without complex nested if
statements.
The Scope of return
Remember that return
exits the entire method it is in, not just a loop or switch
statement. If a return
statement is executed inside a loop, the loop terminates immediately, and control goes back to wherever the method was called from.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static bool FindValue(int[] data, int valueToFind)
{
int index = 0;
while (index < data.Length)
{
if (data[index] == valueToFind)
{
Console.WriteLine($"Value found at index {index}.");
return true; // Exit the FindValue method immediately
}
index++;
}
// This part is only reached if the loop finishes without finding the value
Console.WriteLine("Value not found.");
return false; // Exit the FindValue method
}
The for
Loop: Structured Iteration
While the provided notes focus on while
and do-while
, another extremely common and often more structured loop in C# is the for
loop. It’s particularly useful when you know how many times you want to iterate or when you need an iterator variable that changes predictably.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Syntax:
// for (initializer; condition; iterator)
// {
// Loop body
// }
// Example: Count from 0 to 4
Console.WriteLine("Using a for loop:");
for (int i = 0; i < 5; i++) // 1. Initialize i=0; 2. Check i<5; 4. Increment i++
{
// 3. Execute loop body
Console.WriteLine("i is now: " + i);
}
// Loop finishes when i < 5 becomes false
// Output:
// Using a for loop:
// i is now: 0
// i is now: 1
// i is now: 2
// i is now: 3
// i is now: 4
How it works:
- Initializer (
int i = 0;
): Runs once at the very beginning. Typically declares and initializes a loop counter. - Condition (
i < 5;
): Checked before each iteration (likewhile
). If true, the loop body runs. If false, the loop terminates. - Loop Body (
{...}
): Executes if the condition is true. - Iterator (
i++
): Runs after each execution of the loop body. Typically updates the loop counter.
The for
loop neatly packages the initialization, condition check, and iteration update into one line, making it very clear for standard counting loops.
Nested Control Structures
You can place loops inside other loops, if
statements inside loops, loops inside if
statements, etc. This is called nesting.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Example: Print a small multiplication table (nested for loops)
for (int row = 1; row <= 3; row++)
{
Console.Write($"Row {row}: ");
for (int col = 1; col <= 3; col++)
{
Console.Write($" {row * col} "); // Inner loop runs completely for each outer loop iteration
}
Console.WriteLine(); // Move to next line after inner loop finishes
}
// Output:
// Row 1: 1 2 3
// Row 2: 2 4 6
// Row 3: 3 6 9
When nesting, be mindful of how break
and continue
work – they only affect the innermost loop they are inside.
Advanced switch
(Pattern Matching - Mention)
Modern C# versions have significantly enhanced the switch
statement (and introduced switch
expressions) with pattern matching. This allows you to switch not just on constant values but also on types, property values, and other patterns. While a deep dive is beyond this scope, be aware that switch
is more powerful than just comparing constants.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Conceptual Example (Syntax might vary slightly by C# version)
object shape = GetSomeShape();
switch (shape)
{
case Circle c when c.Radius > 10:
Console.WriteLine("Large circle");
break;
case Circle c:
Console.WriteLine("Small circle");
break;
case Square s:
Console.WriteLine("Square");
break;
case null:
Console.WriteLine("Shape is null");
break;
default:
Console.WriteLine("Unknown shape");
break;
}
Tutorial: Prime Number Checker
Let’s write a program to check if a number is prime, using nested loops and break
.
Objective: Practice using loops, if
conditions, and the break
statement for efficiency.
Definition: A prime number is a whole number greater than 1 that has only two divisors: 1 and itself. (e.g., 2, 3, 5, 7, 11…)
Logic: To check if a number n
is prime, we can try dividing it by all numbers from 2 up to the square root of n
. If we find any number that divides n
evenly (remainder is 0), then n
is not prime, and we can stop checking.
Prerequisites: A C# console project.
Step 1: Get User Input
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
public class Program
{
public static void Main(string[] args)
{
Console.Write("Enter a whole number greater than 1: ");
string input = Console.ReadLine();
int number;
if (!int.TryParse(input, out number) || number <= 1)
{
Console.WriteLine("Invalid input. Please enter a whole number greater than 1.");
return; // Exit the Main method
}
// Prime checking logic goes here
}
}
Step 2: Implement Prime Check Logic
We’ll assume the number is prime initially and use a loop to try and prove it’s not.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// ... inside Main, after input validation ...
bool isPrime = true; // Assume it's prime until proven otherwise
// Loop from 2 up to the square root of the number
// (Checking beyond the square root is redundant)
for (int divisor = 2; divisor * divisor <= number; divisor++)
{
// Check if 'number' is perfectly divisible by 'divisor'
if (number % divisor == 0)
{
isPrime = false; // Found a divisor, so it's not prime
Console.WriteLine($"{number} is divisible by {divisor}.");
break; // Exit the loop - no need to check further divisors
}
}
// Step 3: Display the result (outside the loop)
if (isPrime)
{
Console.WriteLine($"{number} is a prime number.");
}
else
{
Console.WriteLine($"{number} is not a prime number.");
}
}
Explanation: We initialize isPrime
to true
. The for
loop iterates through potential divisors. divisor * divisor <= number
is an efficient way to check up to the square root. If number % divisor == 0
is true, we find a divisor, set isPrime
to false
, print why, and use break
to exit the loop early because we already know the answer. If the loop finishes without finding any divisors (i.e., break
was never hit), isPrime
remains true
.
Step 3: Build and Run
- Save
Program.cs
. - Build (
dotnet build
) and run (dotnet run
). - Test with prime numbers (e.g., 2, 3, 7, 11, 13, 101) and non-prime numbers (e.g., 4, 6, 9, 10, 100).
Example Interaction (Prime):
1
2
Enter a whole number greater than 1: 13
13 is a prime number.
Example Interaction (Not Prime):
1
2
3
Enter a whole number greater than 1: 12
12 is divisible by 2.
12 is not a prime number.
Exercise: Text Analysis
Create a program that analyzes a piece of text entered by the user to count vowels, consonants, and digits.
Project Goal: Practice using loops (for
or while
), if-else if-else
or switch
, and continue
.
Requirements:
- Create a new console project.
- Prompt the user to enter a line of text.
- Read the input string.
- Initialize counters for vowels, consonants, and digits to zero.
- Use a loop to iterate through each character in the input string.
- Inside the loop, for each character:
- Convert the character to lowercase for easier comparison (e.g.,
char lowerChar = char.ToLower(currentChar);
). - Use
if-else if-else
or aswitch
statement to check the character:- If it’s a vowel (‘a’, ‘e’, ‘i’, ‘o’, ‘u’), increment the vowel counter.
- If it’s a digit (‘0’ through ‘9’), increment the digit counter. (Hint:
char.IsDigit(currentChar)
is useful). - If it’s a letter but not a vowel, increment the consonant counter. (Hint:
char.IsLetter(currentChar)
is useful). - If it’s none of the above (e.g., punctuation, space), you can either ignore it or use
continue
to skip to the next character immediately.
- Convert the character to lowercase for easier comparison (e.g.,
- After the loop finishes, print the final counts for vowels, consonants, and digits.
Hints:
- You can loop through a string using a
for
loop:for (int i = 0; i < inputText.Length; i++) { char currentChar = inputText[i]; ... }
- Or using a
foreach
loop:foreach (char currentChar in inputText) { ... }
char.ToLower(c)
converts a characterc
to lowercase.char.IsDigit(c)
returnstrue
ifc
is ‘0’-‘9’.char.IsLetter(c)
returnstrue
ifc
is a letter.
Steps:
- Write the code in
Program.cs
. - Save, build, and run.
- Test with various inputs containing letters, numbers, spaces, and punctuation (e.g., “Hello World 123!”).
Conclusion
This lesson covered techniques for more precise control within loops (break
, continue
), the scope of return
, the common for
loop structure, and the concept of nesting control structures. Understanding these allows you to write more efficient and targeted logic for handling complex conditions and repetitions. While modern C# offers even more advanced control flow features (like pattern matching), mastering these fundamentals provides a very strong foundation.