Programs are not read top-to-bottom
By default, a program runs line 1, line 2, line 3… Control flow is the
set of tools that breaks this: skip lines (decisions), repeat lines
(loops), jump elsewhere (functions — next page). Every feature of every app
reduces to these moves. A thermostat is one if. A spam filter is an if
with a fancy condition. A feed is a loop over posts.
Decisions: if / else if / else
# Python
temperature = 31
if temperature > 35:
print("Heat warning")
elif temperature > 25:
print("Warm day") # ← this runs (31 > 25)
else:
print("Pleasant")
// Java
int temperature = 31;
if (temperature > 35) {
System.out.println("Heat warning");
} else if (temperature > 25) {
System.out.println("Warm day");
} else {
System.out.println("Pleasant");
}
// C++
int temperature = 31;
if (temperature > 35) {
std::cout << "Heat warning\n";
} else if (temperature > 25) {
std::cout << "Warm day\n";
} else {
std::cout << "Pleasant\n";
}
Rules that apply in all three:
- Conditions are checked top to bottom; the first true branch runs,
the rest are skipped. (Order matters: test
> 35before> 25, or the heat warning becomes unreachable.) elseis the catch-all; it's optional.- Python marks the body by indentation; Java/C++ use
{ }braces (and indent anyway, for humans).
Conditions and logic operators
A condition is anything that evaluates to true/false — built from
comparisons (==, !=, <, <=, >, >=) and combined with
logical operators:
| Meaning | Python | Java / C++ | True when |
|---|---|---|---|
| both | and | && | both sides true |
| either | or | || | at least one true |
| flip | not | ! | the operand is false |
age = 20
has_id = True
if age >= 18 and has_id:
print("Entry allowed")
One subtlety worth knowing on day one: evaluation short-circuits. In
a and b, if a is false, b is never evaluated. This isn't trivia — it's
how real code guards against crashes:
if user is not None and user.is_admin: # safe: second check skipped if no user
Loops: doing things many times
for — when you know what you're iterating over
# Python — over a range of numbers...
for i in range(1, 6): # 1, 2, 3, 4, 5 (end is exclusive)
print(i)
# ...or directly over a collection (the more common case)
for item in ["bread", "milk", "eggs"]:
print(item)
// Java
for (int i = 1; i <= 5; i++) { // init; keep-going condition; step
System.out.println(i);
}
for (String item : new String[]{"bread", "milk", "eggs"}) {
System.out.println(item); // "for-each" form
}
// C++
for (int i = 1; i <= 5; i++) {
std::cout << i << "\n";
}
for (const std::string& item : {"bread", "milk", "eggs"}) {
std::cout << item << "\n"; // range-based for
}
while — when you only know the stopping condition
# Python — keep asking until the answer is valid
answer = ""
while answer not in ("yes", "no"):
answer = input("Continue? (yes/no): ")
for = "do this N times / for each thing"; while = "keep going until
something changes." Any for can be rewritten as a while, but using the
one that matches your intent makes code readable.
break and continue
for item in inventory:
if item.damaged:
continue # skip this item, go to the next
if item.id == target:
print("found!")
break # stop the whole loop
The accumulator pattern
Half of all beginner programs are this shape — start with an empty result, fold each item in:
total = 0
for price in [250, 120, 180]:
total += price # total is the "accumulator"
print(total) # 550
Counting, summing, finding-the-max, building a list — all the same pattern. Recognize it now; in Level 3 it grows up to become dynamic programming.
Nesting, and your first taste of complexity
Control flow composes: loops inside loops, ifs inside loops.
# Every pair of students in a class (the "all pairs" shape)
for i in range(len(students)):
for j in range(i + 1, len(students)):
print(students[i], "vs", students[j])
With 30 students that inner line runs 435 times; with 1,000 students, ~500,000 times. A loop inside a loop multiplies work — for n items, roughly n × n = n² steps. This idea has a name, time complexity (written O(n²) — see the complexity cheat sheet), and it's the central obsession of Levels 2–4: most of DSA is the art of replacing an n² loop-in-loop with something smarter.
Common beginner mistakes
- The infinite loop — a
whilewhose condition never becomes false (classically: forgetting thei += 1). Your program hangs; Ctrl-C kills it. Everyone writes one this week. - Off-by-one errors — looping one time too many or too few. Know your
ends: Python's
range(1, 6)excludes 6; Java'si <= 5vsi < 5are different loops. The most common bug family in all of programming. =vs==in conditions — assignment vs comparison (last page); C++ compiles the wrong one silently.- Modifying a list while looping over it — items get skipped as the list shifts under you. Loop over a copy, or build a new list.
- Arrow code — five levels of nested ifs. Prefer guard clauses:
handle the bad cases with an early
return/continue, keep the happy path flat. (This is also a code-review comment you'll receive in your first job.)
Interview perspective
Practice
Beginner
- Print the multiplication table of 7, formatted
7 x 3 = 21. - Loop through
[12, -4, 9, -1, 0, 7]and count negatives, then also track the largest value. (Two accumulators, one loop.) - Classic: print this with nested loops:
* ** *** ****
Intermediate
- FizzBuzz from memory, in two languages, without looking up.
- Guess-the-number: pick a random 1–100, loop reading guesses, print higher/lower, count attempts. (Touches while, if/elif, break.)
- Take a paragraph string and count how many words have more than 5 letters.
Advanced
- Without running it, determine exactly how many times
printexecutes; then verify:Pythonfor i in range(1, 11): for j in range(i, 11): print(i, j) - Refactor this into guard clauses so it nests at most one level:
Python
if user: if user.active: if user.balance > 0: process(user)
Next: Functions — naming your control flow and reusing it.