In the previous lesson you learned how to make your program take decisions with if/else,
but those decisions were only evaluated once. In BiblioTechConsole, though, almost no real
task consists of looking at a single piece of data: you need to go through the entire book
catalog to display it, count how many copies are available, or search for one by title until
it's found (or confirm it doesn't exist). Repeating an action a fixed or an unknown number of
times is the job of loops. In this lesson you'll learn the four loop forms C# offers —
for, while, do-while, and foreach — and how to control them with break and
continue.
Content
- The
forloop - The
whileloop - The
do-whileloop - The
foreachloop - Comparison: when to use each one
breakandcontinue- Nested loops
- Full application: listing, counting, and searching the catalog
- The
for loop
for loopThe for loop is ideal when you know in advance (or can calculate) how many times an action
must be repeated, typically because you're iterating over a collection by index.
string[] bookTitles = { "One Hundred Years of Solitude", "Hopscotch", "Ficciones", "The Aleph" };
for (int i = 0; i < bookTitles.Length; i++)
{
Console.WriteLine($"{i + 1}) {bookTitles[i]}");
}The for header has three parts separated by ;:
| Part | Example | When it runs |
|---|---|---|
| Initialization | int i = 0 |
Once, before starting |
| Condition | i < bookTitles.Length |
Before each iteration; if false, the loop ends |
| Increment (or update) | i++ |
After each iteration |
Using bookTitles.Length in the condition, instead of a fixed number like 4, keeps the loop
from breaking (or failing) if the array's size changes later on.
You can also iterate in reverse, which is useful when elements are going to be removed from a
collection while iterating over it (a topic that will be expanded on with List<T> in Module
4):
- The
while loop
while loopwhile repeats a block while a condition is true, evaluating it before each
iteration. It's the natural choice when you don't know in advance how many times the action
needs to be repeated.
int index = 0;
int availableBooks = 0;
bool[] availability = { true, false, true, true };
while (index < availability.Length)
{
if (availability[index])
{
availableBooks++;
}
index++;
}
Console.WriteLine($"Available books: {availableBooks}");A typical while use case is waiting for valid user input, where you don't know how many
attempts it will take:
string? input = null;
int bookPages = 0;
bool validInput = false;
while (!validInput)
{
Console.Write("Enter the number of pages in the book: ");
input = Console.ReadLine();
validInput = int.TryParse(input, out bookPages);
if (!validInput)
{
Console.WriteLine("Invalid input, try again.");
}
}
Console.WriteLine($"Page count recorded: {bookPages}");Watch out: if a while condition never becomes false, the loop runs forever (an infinite
loop). There must always be, inside the block, some statement that moves the condition
toward its end (in the first example, index++).
- The
do-while loop
do-while loopdo-while is almost identical to while, with one key difference: the condition is
evaluated after the block runs, so the block always executes at least once, even if
the condition was already false from the start.
int attempts = 0;
bool loanRegistered = false;
do
{
attempts++;
Console.WriteLine($"Attempt number {attempts} to register the loan...");
// We simulate the registration succeeding on the second attempt
loanRegistered = attempts >= 2;
} while (!loanRegistered);
Console.WriteLine("Loan registered successfully.");Note the syntax: the while keyword and its condition go after the closing brace, and the
line ends with ;. This pattern fits interactive menus well, where the menu must be displayed
at least once before checking whether the user wants to exit.
- The
foreach loop
foreach loopforeach iterates over all the elements of a collection (an array, or any type that is
"iterable", as you'll see in more detail in Module 4 with collections), without needing to
manually manage an index or a stopping condition.
string[] bookTitles = { "One Hundred Years of Solitude", "Hopscotch", "Ficciones", "The Aleph" };
foreach (string title in bookTitles)
{
Console.WriteLine(title);
}foreach is more readable than for when you don't need the index, but it has an important
limitation: the iteration variable (title in the example) is read-only inside the loop;
you cannot use foreach to modify the array's elements directly through it.
int[] availableCopies = { 2, 0, 1, 3 };
// foreach (int copies in availableCopies)
// {
// copies++; // Compile error: cannot assign to the iteration variable
// }
// If you need to modify the array, use a for loop with an index:
for (int i = 0; i < availableCopies.Length; i++)
{
availableCopies[i]++;
}
- Comparison: when to use each one
| Loop | Use it when... | It evaluates the condition... |
|---|---|---|
for |
You know (or can calculate) the number of iterations, or you need the index | Before each iteration |
while |
You don't know how many iterations will be needed, and it could be zero | Before each iteration |
do-while |
Like while, but the block must run at least once |
After each iteration |
foreach |
You just need to go through all the elements, without an index or modifying them | Before each iteration (internally) |
In practice, for and foreach cover the vast majority of traversals over arrays and
collections in BiblioTechConsole; while and do-while are reserved for situations where the
stopping condition depends on something other than "going through a full collection", such as
validating user input or waiting for an external condition to be met.
break and continue
break and continueInside any loop, two keywords let you alter the normal iteration flow:
break: ends the loop immediately, without evaluating any further iterations.continue: skips the rest of the loop body in the current iteration and moves straight to the next one.
string[] bookTitles = { "One Hundred Years of Solitude", "Hopscotch", "Ficciones", "The Aleph" };
string searchedTitle = "Ficciones";
for (int i = 0; i < bookTitles.Length; i++)
{
if (bookTitles[i] == searchedTitle)
{
Console.WriteLine($"Found at position {i}.");
break; // no need to keep scanning the array
}
}bool[] availability = { true, false, true, true, false };
for (int i = 0; i < availability.Length; i++)
{
if (!availability[i])
{
continue; // skip books that aren't available
}
Console.WriteLine($"Book at position {i}: available");
}break also works inside while, do-while, and foreach; so does continue.
- Nested loops
A loop can contain another loop inside it. This is common when working with two-dimensional arrays (which you already saw in the arrays lesson), for example, to represent a map of shelves and shelf levels in BiblioTech:
string[,] shelfMap = new string[2, 3]
{
{ "Fiction", "Fiction", "Non-fiction" },
{ "Poetry", "Children's", "Children's" }
};
for (int shelf = 0; shelf < 2; shelf++)
{
for (int shelfLevel = 0; shelfLevel < 3; shelfLevel++)
{
Console.WriteLine($"Shelf {shelf}, level {shelfLevel}: {shelfMap[shelf, shelfLevel]}");
}
}The outer loop iterates over shelves; for each shelf, the inner loop iterates over its
levels. In total, 2 × 3 = 6 iterations run. Keep in mind that break and continue only
affect the innermost loop they're in; if you need to exit both loops at once, a simple
technique is to use a boolean variable as a flag:
bool found = false;
for (int shelf = 0; shelf < 2 && !found; shelf++)
{
for (int shelfLevel = 0; shelfLevel < 3; shelfLevel++)
{
if (shelfMap[shelf, shelfLevel] == "Non-fiction")
{
Console.WriteLine($"Genre found at shelf {shelf}, level {shelfLevel}");
found = true;
break;
}
}
}
- Full application: listing, counting, and searching the catalog
Let's combine everything above into three typical operations on the BiblioTechConsole catalog: listing the titles, counting how many are available, and searching for one by title.
string[] bookTitles = { "One Hundred Years of Solitude", "Hopscotch", "Ficciones", "The Aleph", "Pedro Páramo" };
bool[] availability = { true, false, true, true, false };
// 1) List all titles with their status (foreach won't work here because we need the index)
Console.WriteLine("=== BiblioTech Catalog ===");
for (int i = 0; i < bookTitles.Length; i++)
{
string status = availability[i] ? "Available" : "On loan";
Console.WriteLine($"{i + 1}) {bookTitles[i]} - {status}");
}
// 2) Count how many books are available (foreach: we don't need the index)
int totalAvailable = 0;
foreach (bool isAvailable in availability)
{
if (isAvailable)
{
totalAvailable++;
}
}
Console.WriteLine($"Total available books: {totalAvailable}");
// 3) Search for a specific title and stop as soon as it's found
string searchedTitle = "Ficciones";
bool found = false;
for (int i = 0; i < bookTitles.Length; i++)
{
if (bookTitles[i] == searchedTitle)
{
Console.WriteLine($"'{searchedTitle}' found at position {i + 1}, available: {availability[i]}");
found = true;
break;
}
}
if (!found)
{
Console.WriteLine($"'{searchedTitle}' is not in the catalog.");
}This snippet already combines a for (when the index matters), a foreach (when only the
value matters), and break (to stop a search as soon as the result is found): three
deliberate decisions, not arbitrary ones.
Common Mistakes and Tips
- Infinite loops: forgetting to update the control variable in a
while(for example, not incrementing the index) leaves the program hanging forever. Always double-check that the condition can eventually becomefalse. - Overflowing an array's index: in a
forloop, using<=instead of<againstarray.Lengthcauses access to a position that doesn't exist and throws an exception at runtime (you'll see this in detail in the last lesson of the module). - Trying to modify the
foreachvariable: as shown, this doesn't compile. If you need to modify the elements, useforwith an index. - Using
forwhenforeachis clearer (and vice versa): if you don't need the index, preferforeach; it improves readability and reduces the risk of indexing mistakes. - Confusing
breakwithcontinue:breakexits the entire loop;continueonly skips to the next iteration. Using the wrong one often produces incomplete results or loops that end too early. - Nesting loops unnecessarily: before nesting two loops, check whether the problem can be solved with a single pass; nesting multiplies the number of iterations (and the running time) and adds complexity.
Exercises
-
Given the array
int[] availableCopies = { 3, 0, 5, 2, 0 };, use aforloop to iterate over it and print to the console how many positions have0available copies (out-of-stock books). -
Use a
whileloop to simulate validating an administrator password: start fromstring attempt = "";and a simulated list of valid attemptsstring[] simulatedAttempts = { "1234", "abcd", "bibliotech" };(walk this array with an increasing index on each pass of thewhile, as if they were successive user attempts). The loop must stop as soon asattemptequals"bibliotech", displaying how many attempts it took. -
Given the array of titles
string[] bookTitles = { "One Hundred Years of Solitude", "Hopscotch", "Ficciones", "The Aleph" };, iterate over the array withforeachand, usingcontinue, print to the console only the titles that have more than 9 characters.
Solutions
int[] availableCopies = { 3, 0, 5, 2, 0 };
int outOfStockBooks = 0;
for (int i = 0; i < availableCopies.Length; i++)
{
if (availableCopies[i] == 0)
{
outOfStockBooks++;
}
}
Console.WriteLine($"Out-of-stock books: {outOfStockBooks}");
The result is 2, corresponding to positions 1 and 4 (indices starting at 0).
string[] simulatedAttempts = { "1234", "abcd", "bibliotech" };
string attempt = "";
int index = 0;
int attemptCount = 0;
while (attempt != "bibliotech")
{
attempt = simulatedAttempts[index];
attemptCount++;
index++;
}
Console.WriteLine($"Correct password found after {attemptCount} attempt(s).");
The result shows 3 attempts, because "bibliotech" occupies the third position in the
simulated array (index 2). Notice that the while condition is evaluated before each pass,
so the last check (attempt != "bibliotech", now false) is the one that stops the loop
without running an extra pass.
string[] bookTitles = { "One Hundred Years of Solitude", "Hopscotch", "Ficciones", "The Aleph" };
foreach (string title in bookTitles)
{
if (title.Length <= 9)
{
continue;
}
Console.WriteLine(title);
}
Only "One Hundred Years of Solitude" (29 characters) is printed, since it's the only
title with more than 9 characters. "Hopscotch", "Ficciones", and "The Aleph" are all
exactly 9 characters long, so the continue skips all three without printing anything for
them. This is a good exercise to check with Console.WriteLine(title.Length) how the
result changes if you use < instead of <=.
Conclusion
In this lesson you've learned to repeat actions with for, while, and do-while, to
iterate over collections easily with foreach, to control a loop's flow with break and
continue, and to combine nested loops when data has more than one dimension. With these
tools, BiblioTechConsole can now list its full catalog, count available books, and search for
specific titles without repeating code by hand.
So far, to classify something (like the status of a loan) you've used chains of
if/else if/else. In the next lesson, Switch Statements, you'll learn a clearer
alternative for when you need to compare the same variable against many possible values, for
example, to classify a book by its category or genre within BiblioTech.
C# Programming Course
Module 1: Introduction to C#
- Introduction to C#
- Setting Up the Development Environment
- Hello World Program
- Basic Syntax and Structure
- Variables and Data Types
- Arrays and Strings
Module 2: Control Structures
Module 3: Object-Oriented Programming
- Classes and Objects
- Methods
- Constructors and Destructors
- Inheritance
- Polymorphism
- Encapsulation
- Abstraction
- Structs and Records: Value Types and Reference Types
Module 4: Advanced C# Concepts
- Interfaces
- Delegates and Events
- Pattern Matching and Modern C# Features
- Generics
- Collections
- LINQ (Language Integrated Query)
- Asynchronous Programming
Module 5: Working with Data
- File I/O
- Serialization
- Database Connectivity
- Entity Framework
- Working with JSON and Consuming REST APIs
Module 6: Advanced Topics
- Reflection
- Attributes
- Dynamic Programming
- Memory Management and Garbage Collection
- Multithreading and Parallel Programming
Module 7: Building Applications
Module 8: Best Practices and Design Patterns
- Coding Standards and Best Practices
- Design Patterns
- Dependency Injection and Inversion of Control
- Unit Testing
- Code Review and Refactoring
