Loops
Computers are good at doing the same thing many times without getting bored: printing a table, adding up a thousand bills, asking again until the input is valid. A loop repeats a block of code while a condition is true or once for each item in a collection.
C# has four loops: for, while, do-while and foreach. In this lesson you will learn when to use each one, how break and continue change the flow, and how to avoid the two classic loop bugs.
The for loop
Use for when you know how many times to repeat, usually with a counter. Its header has three parts separated by semicolons: start, condition and step.
for (int i = 1; i <= 5; i++)
{
Console.WriteLine($"17 x {i} = {17 * i}");
}
for (int countdown = 10; countdown > 0; countdown -= 3)
{
Console.Write($"{countdown} ");
}
Console.WriteLine("Lift-off!");17 x 1 = 17 17 x 2 = 34 17 x 3 = 51 17 x 4 = 68 17 x 5 = 85 10 7 4 1 Lift-off!
The loop runs like this: set i = 1; check i <= 5; if true, run the block; do the step i++; check again; and so on. When the condition becomes false, the loop ends. The step can be anything, such as countdown -= 3.
The variable i exists only inside the loop. After the closing brace, using i is a compile error, which keeps loop counters from leaking into the rest of your code.
The while loop
Use while when you do not know in advance how many times to repeat. It checks the condition before every pass, so the body may run zero times.
decimal savings = 0m;
decimal monthly = 1500m;
int months = 0;
while (savings < 10000m)
{
months++;
savings += monthly;
}
Console.WriteLine($"Ananya reaches her laptop goal in {months} months.");
Console.WriteLine($"Saved: Rs {savings}");Ananya reaches her laptop goal in 7 months. Saved: Rs 10500
Something inside the loop must eventually make the condition false. Here savings grows every month. If you forgot savings += monthly;, the loop would run forever: an infinite loop. Press Ctrl+C in the terminal to stop a program stuck like that.
The do-while loop
A do-while loop checks its condition after each pass, so the body always runs at least once. That makes it perfect for menus.
string? choice;
int balance = 5000;
do
{
Console.WriteLine("1. Check balance 2. Exit");
Console.Write("Choose: ");
choice = Console.ReadLine();
if (choice == "1")
{
Console.WriteLine($"Balance: Rs {balance}");
}
} while (choice != "2");
Console.WriteLine("Thank you for banking with us.");1. Check balance 2. Exit Choose: 1 Balance: Rs 5000 1. Check balance 2. Exit Choose: 2 Thank you for banking with us.
Note the semicolon after while (choice != "2"): a do-while is the only loop that ends with one.
The foreach loop
foreach visits every item of an array or collection, in order, without any counter. It is the loop you will write most often in real C#.
int[] balls = [1, 0, 4, 0, 6, -1, 2];
int runs = 0;
foreach (int ball in balls)
{
if (ball == -1)
{
Console.WriteLine("Wicket! Innings over.");
break;
}
if (ball == 0)
{
continue; // dot ball: nothing to add
}
runs += ball;
Console.WriteLine($"Scored {ball}, total {runs}");
}
Console.WriteLine($"Final score: {runs}");Scored 1, total 1 Scored 4, total 5 Scored 6, total 11 Wicket! Innings over. Final score: 11
Two keywords control any loop:
breakleaves the loop immediately. The last ball,2, is never read.continueskips the rest of this pass and moves on to the next item.
The loop variable in foreach is read-only: ball = 5; inside the loop is a compile error. Also, you must not add or remove items from a list while a foreach is walking through it; that throws InvalidOperationException: Collection was modified; enumeration operation may not execute.
Nested loops
A loop can contain another loop. The inner loop runs completely for every single pass of the outer loop. Here is a small seat map for a bus:
string[] rows = ["A", "B", "C"];
foreach (string row in rows)
{
for (int seat = 1; seat <= 4; seat++)
{
Console.Write($"{row}{seat} ");
}
Console.WriteLine();
}A1 A2 A3 A4 B1 B2 B3 B4 C1 C2 C3 C4
Three rows times four seats gives twelve inner passes. Nested loops are common for tables, grids and comparing every item with every other item, but they get slow quickly: 1,000 outer passes times 1,000 inner passes is a million.
Loops and ranges of numbers
For a simple run of numbers, Enumerable.Range(start, count) produces them for a foreach, and LINQ methods such as Sum can often replace a loop entirely. You will learn LINQ in LINQ.
int total = 0;
foreach (int n in Enumerable.Range(1, 100))
{
total += n;
}
Console.WriteLine(total);
Console.WriteLine(Enumerable.Range(1, 100).Sum());5050 5050
Common mistakes
- Off-by-one errors. For an array of length 5, valid indexes are 0 to 4.
for (int i = 0; i <= arr.Length; i++)readsarr[5]and throwsIndexOutOfRangeException. Use<withLength. - Infinite loops. The condition never becomes false because the variable is never updated. Check that every
whilechanges something it tests. - A semicolon after the header.
for (int i = 0; i < 5; i++);runs an empty body five times, then the block below runs once. - Changing a collection inside
foreach. Collect the changes and apply them after the loop, or loop backwards withfor. - Using
whilewhereforeachfits. Manual counters are easy to get wrong; letforeachdo the work.
Key points
for (start; condition; step)repeats with a counter.whilechecks before each pass;do-whilechecks after, so it runs at least once.foreachvisits each item of an array or collection; its variable is read-only.breakexits a loop;continuejumps to the next pass.- Inner loops run fully for each pass of the outer loop.
- Watch for off-by-one errors and conditions that never become false.
Exercise
A school in Jaipur collects fees in instalments. Write a program with an array of payments [2500, 3000, 0, 4500, 3000] (0 means a month was missed). Use a loop to print each month's payment, skip missed months with continue after printing "Month 3: missed", and stop with break as soon as the total reaches at least Rs 10,000. Finally, print the total collected.
Show solution
int[] payments = [2500, 3000, 0, 4500, 3000];
int total = 0;
for (int i = 0; i < payments.Length; i++)
{
int month = i + 1;
if (payments[i] == 0)
{
Console.WriteLine($"Month {month}: missed");
continue;
}
total += payments[i];
Console.WriteLine($"Month {month}: Rs {payments[i]} (total Rs {total})");
if (total >= 10000)
{
Console.WriteLine("Fee target reached.");
break;
}
}
Console.WriteLine($"Collected: Rs {total}");Month 1: Rs 2500 (total Rs 2500) Month 2: Rs 3000 (total Rs 5500) Month 3: missed Month 4: Rs 4500 (total Rs 10000) Fee target reached. Collected: Rs 10000
A for loop fits because the month number comes from the index. continue skips the adding for the missed month, and break stops before month 5 is read.
Quick Quiz
1. How many times does for (int i = 0; i < 4; i++) run its body?
i takes the values 0, 1, 2 and 3; when it reaches 4 the condition is false.
2. Which loop always runs its body at least once?
do-while checks the condition after the body, so the first pass always happens.
3. What does continue do inside a loop?
continue jumps straight to the next pass; break is the one that exits.
4. What happens if you remove items from a List while a foreach loops over it?
Changing a collection during foreach throws "Collection was modified; enumeration operation may not execute."
Learn C# with a mentor
Free lessons get you started. Our Programming & Software Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
