C# For and Foreach: Count Positions and Visit Values Clearly
Choose for when positions or counts matter, and foreach when the work needs each value. Learn to separate zero-based indexes from display numbers, preserve source data, and verify empty and changing collections.
What you will understand
- Trace initializer, condition, body and iterator in order.
- Explain zero-iteration loops and counter scope.
- Preview a fixed array and its valid zero-based positions.
- Distinguish a position from a human-readable row number.
- Use foreach to visit values without manual indexing.
- Accumulate totals and counts outside the repeated body.
- Distinguish a display transformation from a collection update.
- Test empty, single-item, longer and repeated-value collections.
Put counted repetition into a readable for header
A for loop gathers a starting state, a continuation condition and an update in one header. It is useful when a count or position is central to the work. It does not remove the need to explain how that state approaches a stopping boundary.
Read the order carefully: initialize once, check the condition, run the body, run the iterator, then check again. The iterator is not run before the first body. If the first condition is false, no body or iterator executes. This is the same before-body checking principle you learned with while.
You need variables, operators and the While lesson. This lesson also previews small arrays so there are real values to visit; array creation and updates are covered in their own later lesson. Every editor is a complete program. Two examples intentionally fail compilation and one intentionally fails at runtime.
Program.cs · Read the three parts of a for header
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Step 1
Step 2
Step 3
Finished.
The initializer runs once. The condition is tested before each body. The iterator step++ runs after a completed body, before the next condition check. The semicolons separate these header parts; they are not commas and do not mean every part executes on every pass.
Program.cs · A false first condition skips the body
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
No iterations needed.
The initializer runs, then 0 < 0 is false. The body and iterator do not run. Like while, for allows zero iterations. This makes an empty collection or zero requested repetitions a normal case rather than a special first-item access.
Program.cs · Choose an update that reaches the boundary
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Even label: 2
Even label: 4
Even label: 6
Remaining: 3
Remaining: 2
Remaining: 1
The update can add a step or count downward. It must move the state toward a false condition for these finite loops. Check the start, direction and boundary together. The examples use small integers; an arbitrary large counter also requires attention to overflow.
Let the counter’s scope match its purpose
A variable declared in a for initializer belongs to that loop statement. You can use it in the condition, body and iterator, but not in a later statement outside the loop. This keeps a temporary traversal detail from leaking into unrelated code.
An accumulator or final count needed afterward belongs in an outer scope. That does not require moving every loop variable outside. Name the role clearly: index selects a position, displayedCount counts printed rows and total holds an accumulated amount.
A for loop does not inherently know how many times it should run. Its header can even omit parts, but optional syntax is not a reason to hide the stopping rule. Keep all three parts explicit while learning and avoid updating the same counter again inside the body.
Program.cs · A header variable belongs to its loop
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Compilation fails: index is not in scope after the loop.A local declared in the for initializer is accessible in its condition, iterator and body, not after the statement. Declare a value outside when its final state is genuinely needed afterward. Do not broaden scope merely to reuse the same counter across unrelated loops.
An element position and a human-readable number are different
An array stores an ordered collection of values of an element type. string[] means an array of strings. The brace initializer in this lesson supplies a few fixed values. Length counts elements, and square brackets access one element by its zero-based position.
For a nonempty array of length three, valid indexes are zero, one and two. Use index < titles.Length, not <=. The latter allows an extra iteration and an out-of-range access after the valid output. A collection can print every intended item before still failing on the next check.
A numbered list usually starts its visible labels at one. Add one for the output while keeping the actual index zero-based. Starting the index at one instead skips the first element, and a plausible-looking list number can hide that missing data.
Program.cs · Preview a small fixed collection
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Items: 3
First: Variables
string[] is an array of strings, and the initializer supplies three ordered values. This is a small collection preview for learning iteration; the later Arrays lesson covers arrays in detail. Length is the number of elements, and the first index is zero. These fixed titles are non-null strings.
Program.cs · Keep the index separate from the display number
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
1. Variables
2. Conditions
3. Loops
The array is accessed with zero-based index, while index + 1 creates the human-readable number. The strict less-than condition excludes Length, which is beyond the final element. Do not use the display number directly as the array index.
Program.cs · Length itself is not a valid element index
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Variables
Loops
Then execution fails with IndexOutOfRangeException.The two valid positions are zero and one. The inclusive <= also permits two, so a later iteration fails after both valid titles have already printed. Seeing correct initial output does not prove that the final loop boundary is correct.
Use foreach when each value is enough
foreach expresses for each value in this collection. The body receives an iteration variable with the current element. For the arrays shown here, values are visited in their stored order. No manual position or collection-boundary expression is needed.
An explicit string title states the element type; var title can let the compiler infer it from this array. Neither means the variable can accept arbitrary types. Choose clear names describing a single value, such as title or duration, rather than a vague counter name.
An empty array causes zero body executions. A null collection is not an empty one and needs a presence policy before enumeration. Order guarantees also depend on the kind of collection: this lesson uses arrays rather than promising a meaningful ordering for every enumerable source.
Program.cs · Visit each value without maintaining an index
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Read: Variables
Read: Conditions
Read: Loops
foreach gives the body each array value in order. No index initialization, Length comparison or index increment is needed. Use this when the value is what the work needs. var title would infer string for this array; it would not make the variable dynamically typed.
Program.cs · An empty array is a valid zero-item input
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Items: 0
Array.Empty<string>() supplies an empty string array. The foreach body never runs. An empty array is not null: null means the collection is absent and needs its own policy before enumeration. The Array helper syntax is introduced only to make the zero-item case explicit.
Keep totals and display counters outside the body
An accumulator is initialized once before enumeration, updated for each value and read afterward. Resetting it inside the body would discard previous progress. The same principle applies to a display counter needed for both row labels and a final summary.
foreach visits elements, not distinct values. If the array contains the same title twice, it is visited twice. Removing duplicates is a separate data-processing decision and is not part of simply traversing the collection.
Decide what one iteration represents. In the time example, it is one supplied duration added once. In the lab, it is one title printed once and one display-count increment. A separate calculation of a source Length does not prove that every row was actually displayed.
Program.cs · Accumulate values outside the repeated body
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Total minutes: 30
Initialize total before enumeration so it survives between iterations. Each supplied duration contributes once. Repeated values would still contribute separately, because foreach visits elements rather than unique values. This sum assumes small nonnegative durations and does not validate a real activity log.
Visiting a value is different from updating the collection
The ordinary foreach iteration variable is not an assignment target. Trying to replace title inside the loop fails compilation. If the goal is a transformed label, assign the transformation to a separate local value and print that.
When a position or element assignment is central to the task, an indexed for may be a better fit. You will study array updates later. Do not conclude that changing a copied value automatically writes it back to the collection, or that string methods mutate the stored text.
Modifying general collections while they are being enumerated has additional rules and may invalidate an enumerator. Keep that separate from this lesson’s read-only traversal. The examples deliberately preserve their source array and transform only output labels.
Program.cs · The ordinary iteration variable is not an assignment target
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Compilation fails: the foreach iteration variable cannot be assigned here.The ordinary foreach variable cannot be reassigned. For a transformed display, store a separate result and print it. Updating collection elements is a different task, not something this assignment performs. Advanced ref iteration is outside this beginner lesson.
Program.cs · Transform a display copy without rewriting the collection
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
LOOPS
STRINGS
Original first: Loops
The new local label holds a transformed result. The original string values in titles are unchanged. A display transformation is not a collection update. General collection mutation during enumeration has additional rules and should not be inferred from this simple array of immutable strings.
Choose the loop by the work, then test its boundaries
Use for when you need the index, a particular sequence of positions or a specified count. Use foreach when the work needs each value without manual traversal state. Use while when repetition is driven by a changing condition such as input or a retry state. These are readability choices, not a claim that one loop is always faster.
Test an empty collection, one element, several elements and repeated values. Verify both the first and last output and the summary count. A hardcoded boundary of three may work for the reference input but fail when the collection changes.
Also inspect how much work a body performs. Nested loops multiply their work across outer and inner iterations, so do not add a second loop merely to generate a row label. The reading-list lab needs one traversal and one counter; its result should stay correct when titles are added or removed.
Guided repair: stop skipping the first title
The numbered output begins with Conditions instead of Variables. Explain how a one-based starting index hides a skipped element, then repair both indexing and visible numbering.
Program.cs · Starting at one skips the first element
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
1. Conditions
2. Loops
The first array element is never visited because the index starts at one. The displayed list still begins with 1, hiding the skipped value if you check labels alone. Compare the output’s actual titles with the source collection.
Repair checkpoints
- Start the array position at zero.
- Use a strict Length boundary so the last valid element is included without overrun.
- Use index + 1 only for the display label.
- With one source title, print that title as row 1.
- With an empty array, print no rows and do not access a first element.
Reveal the repair and explanation
Program.cs · Start at zero and number only the output
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
1. Variables
2. Conditions
3. Loops
Zero-based indexing visits the first element, the strict boundary visits the last without overrunning it, and + 1 supplies a display label. Changing the array length now changes the number of rows automatically without a separate hardcoded count.
Independent lab: a numbered reading list
Create a numbered reading list using foreach. Visit each supplied title in order, print one row per value, and report exactly how many rows were displayed. The output must adapt to the source array without a hardcoded length.
Acceptance checklist
- Use the fixed three-title array from the starter for the reference run.
- Use foreach for the traversal and a counter declared outside the loop.
- Increment the counter exactly once for every printed title.
- Print labels beginning at 1 without skipping the first value.
- Finish with Items displayed: 3 for the reference input.
- Preserve the source titles and handle an empty array as zero rows.
- Assume the supplied titles are non-null; defining a missing-title policy is outside this fixed-data exercise.
Program.cs · Reading-list starter
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
1. Conditions
2. Loops
Items displayed: 2
The summary honestly counts two rows, but the source contains three. Repair the traversal without hardcoding titles or a length of three. The lab asks for foreach so that visiting values and numbering the display have separate, readable roles.
Show hints
- foreach supplies the value; a separate counter supplies numbering.
- Initialize displayedCount before the loop and increase it before printing the row.
- Do not use titles[0] as a special first-row case; the traversal should handle every size.
Reveal the reference solution
Program.cs · Reading-list reference solution
Predict the result, edit Program.cs, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
1. Variables
2. Conditions
3. Loops
Items displayed: 3
foreach handles visiting every value; displayedCount handles human-readable numbering and the final summary. The count increases exactly once per row. With an empty array the body is skipped and the summary remains zero. These fixed titles are present strings; a later real-data pipeline would need an explicit policy for missing or blank titles.
Changed-input checks
- An empty array prints only Items displayed: 0.
- One title prints row 1 and a count of 1.
- Adding a fourth title prints four ordered rows and a count of 4.
- Two identical titles are both displayed and counted; traversal does not deduplicate.
- The original title strings retain their spelling after the report.
Recap: choose positions or values
Use for when position matters, foreach when values are enough, and an outer accumulator when a result must survive the traversal. Check both the first and final elements.
for (start; condition; update)- Counted or position-based repetition with explicit progress.
index < values.Length- Stay inside the valid zero-based positions of an array.
index + 1- Create a human-readable label without changing the array position.
foreach (string value in values)- Visit each string value without maintaining an index.
var iteration variable- Infer its compile-time type from the collection element type.
outer accumulator- Retain a total or displayed count across iterations and afterward.
separate display local- Keep the result of a transformation without reassigning the iteration variable.
empty collection- A normal zero-item traversal, distinct from an absent null collection.
Frequently asked questions
Does a for iterator run before the first body?
No. Initialization happens once, then the condition is checked. The iterator follows each completed body before the next condition check.
Why is <= Length usually wrong for an array index?
Length is the number of elements, not the last valid position. Valid positions end at Length - 1, so use index < Length.
Is foreach always better than for?
Choose based on the work. foreach is clear for values; for is useful when position or a counted sequence matters. Do not infer a universal performance advantage.
Does foreach remove duplicate values?
No. It visits every element supplied by the source, including repeated values.
Can I assign a new value to the ordinary foreach variable?
No. Use a separate transformed display variable. Updating collection elements is a separate task that may require an indexed approach or another deliberate design.
Does an empty collection throw?
An empty array simply produces zero iterations. A null collection is absent and requires a separate policy before enumeration.
Can you trace the traversal?
Trace header order, valid indexes, value traversal and accumulated counts. Read the explanation after checking your answers.
Next step and references
For and foreach describe different kinds of traversal. Keep indexes zero-based, make display numbers separately, preserve transformation results and test empty or changing source collections.
Next is C# Break and Continue. You will stop a search or skip unsuitable entries while keeping the loop’s purpose clear.
Official references
Original SovranCode explanations, examples and exercises. Technical details were checked against these references.
Last updated: .