Problem overview
The program has an array of three foods and should print a greeting once, followed by one line per food:
I'm hungry!
I'll eat some pasta
I'll eat some burgers
I'll eat some pizza
The buggy version prints I'm hungry! before every food instead of once:
I'm hungry!
I'll eat some pasta
I'm hungry!
I'll eat some burgers
I'm hungry!
I'll eat some pizza
The food lines are right. Only the position of one statement is wrong.
Approach
In C#, the braces after foreach (...) mark the loop body, and every statement inside them runs once for each element of the array. A statement outside the braces runs once. So the question for each line is: should this happen once, or once per food?
I'm hungry!is a one-time announcement, so it belongs outside the loop.I'll eat someplus the food changes with every element, so it belongs inside.
The buggy code has both statements in the body, so the announcement repeats with each food.
Step by step
- Find the line that repeats. The extra output is
I'm hungry!, so the call that prints it is the one in the wrong place. - Move it above the loop. Put
Console.WriteLine("I'm hungry!");before theforeachline. Program flow goes top to bottom, so it now runs first, and only once. - Leave the loop body with just the food line.
Console.WriteLine("I'll eat some " + food);still uses the loop variablefood, so it has to stay inside the braces.
The solution in C#
string[] foods = {"pasta", "burgers", "pizza"};
Console.WriteLine("I'm hungry!");
foreach (string food in foods) {
Console.WriteLine("I'll eat some " + food);
}
Reading it as the computer does: the array is created, I'm hungry! is printed, then the loop runs three times, with food holding "pasta", then "burgers", then "pizza". When the array has no more elements, the loop ends and the program has nothing left to do.
Tracing both versions
Tracing the buggy version shows where the repeats come from. Each pass through the body runs both statements, so the output grows by two lines per food:
| Pass | food | Buggy version prints | Fixed version prints |
|---|---|---|---|
| Before the loop | none | nothing | I'm hungry! |
| 1 | "pasta" | I'm hungry! / I'll eat some pasta | I'll eat some pasta |
| 2 | "burgers" | I'm hungry! / I'll eat some burgers | I'll eat some burgers |
| 3 | "pizza" | I'm hungry! / I'll eat some pizza | I'll eat some pizza |
In the fixed version the loop body is a single statement, which is the only one that depends on the current food.
Edge cases and common mistakes
- Moving the wrong line. Moving the food line out of the loop would not compile, because
foodexists only inside the braces. The compiler reports that the name does not exist in the current context. - Placing the announcement after the loop. That prints the same lines but in a different order, with
I'm hungry!at the end. The tests check the exact order of the output. - Trusting the indentation. C# decides what is in the loop by the braces, not by how the lines are indented. Keep both consistent so the code reads the way it runs.
- An empty array. With the fixed code, an empty
foodsarray would still printI'm hungry!once and then nothing else, because the announcement is outside the loop. - Adding a counter to skip repeats. Beginners sometimes add a flag variable so the announcement prints only on the first pass. That works, but it adds code for no gain. When a statement should run once before the loop, place it before the loop.
- Wanting different text for each pass. If a message must differ per food, it has to use
food. A message that never mentions the loop variable prints the same text every time, so ask whether it belongs in the loop at all.