Conditions and Loops
A program becomes useful when it can choose a response and repeat a reliable action. Learn to turn program state into precise comparisons, order multi-branch decisions, and repeat only while a clear stopping rule remains true. You will trace what happens at exact boundaries—not merely memorize C syntax.
Use state, a question, and a next step
if/else if/else chain with braces.for loop for a known count and a while loop for a changing state.A condition asks one small, testable question
In C, 0 acts as false and a nonzero numeric value acts as true. Most beginner conditions are clearer when they state a relationship directly: completed < total, score >= pass_mark, or attempts != limit. Read such a condition as a sentence before deciding what the program should do next.
Variables hold facts such as a score, remaining count, or current loop index.
A relational or equality operator turns those facts into a true or false result.
if runs its body only when the condition is true; else handles the alternative.
A loop update changes the value that the next condition will examine.
Read a condition in three passes
Do not begin by looking at the braces. First identify the values being read, then state the comparison in ordinary language, and only then choose the branch. For completed < total, the values are completed and total; the question is “are there lessons left?”; the true branch is the work for an unfinished path. This habit makes conditions easier to test and easier to change.
State
A variable stores the current fact. Its name should tell you what the number means before you see an operator.
Reference point
Another value establishes the target, limit, or boundary that makes the first value meaningful.
Question
The comparison is true because 3 is less than 4. It is a question, not an instruction to change data.
Consequence
The branch should say what the program does when the answer to the question is true.
Compare values; do not accidentally replace them
Equality needs two characters. A single = assigns a value to a variable; == compares two values. Write the comparison first, then use braces even when a branch currently has one statement. Braces make a later edit less likely to quietly change which code is controlled.
Equal to
True when both numeric values are the same.
Not equal to
True when two numeric values differ.
Less than
Use <= when the endpoint belongs in the range.
Greater than
Use >= when the passing boundary belongs in the range.
Both true
Logical AND requires the condition on each side to be true.
Either or inverse
Logical OR accepts either side; ! reverses a true or false result.
Choose exactly one response with if and else
The branch below has a complete rule: a learner needs both a passing score and a submitted project. The && operator means both parts must be true. Change the values, predict which message will appear, and run the program. Try a score below 70, then keep the score high and change project_submitted to 0.
Select one completion message
The safe runner evaluates numeric comparisons, &&, ||, and ! without evaluating arbitrary browser code. Edit one value at a time and trace the selected branch.
Edit the program, predict its output, then run it.
if
The body runs only if the condition evaluates to true. The braces visibly mark the controlled statements.
else
This alternative body runs only if the directly preceding if condition is false.
Logical AND
Every required condition must hold. Keep each part independently meaningful and easy to test.
Range rejection
Either impossible boundary makes the full condition true, so one branch can reject invalid data.
Order a multi-branch decision from most specific to least specific
An if/else if/else chain asks questions from top to bottom and runs the first true body only. It does not run every true condition. That makes order part of the rule: a distinction score is also a passing score, so the distinction test must appear before the broader pass test. The final else is the one remaining outcome after all earlier questions are false.
Classify a score with an ordered decision
The runner checks the branches from top to bottom and stops at the first true condition. Change score to 85, 70, 50, and 49; predict the label before you run it.
Edit the program, predict its output, then run it.
- 01Start with score = 72
The first question is
score >= 85. It is false, so C moves to the nextelse if. - 02Test the next boundary
score >= 70is true. The program enters that body and printsPass. - 03Skip every later alternative
The 50-point condition and final
elseare not tested as separate outcomes after one branch has already been chosen. - 04Test the exact edges
Use 85, 70, 50, and 49. Boundaries reveal whether
>=and your branch order match the rule you meant to write.
Combine questions without hiding the rule
Use && when every requirement must hold and || when any invalid state should trigger the same response. C evaluates ! before comparisons, comparisons before &&, and && before ||. You do not need to rely on that order for a complicated rule: parentheses can make the intended grouping visible.
All requirements
Parentheses separate the score question from the submission flag. Both must be true to complete the full condition.
Invalid range
Either impossible side makes the condition true, so a single branch rejects data that is too small or too large.
Negation
Read this as “choice is not 1.” Prefer choice != 1 when it says the same thing more directly.
Group intentionally
Without parentheses, && binds more tightly. The parentheses make “either a or b, and ready” explicit.
Use for when the count is visible from the start
A for loop places its three moving parts together: initialization runs once, the condition is checked before every cycle, and the update runs after the body. This structure fits numbered lessons, days, pages, retries with a fixed limit, and any task whose number of repetitions is known before the loop begins.
Trace a counted practice loop
The loop starts day at 1, runs while day is at most total_days, then changes day with day++. Change total_days and trace the exact number of terminal lines.
Edit the program, predict its output, then run it.
- 01Initialize once
int day = 1creates the starting index before the first condition check. - 02Test before the body
day <= total_daysdecides whether another cycle is allowed. - 03Run one cycle
The body prints one labeled practice day using the current index.
- 04Update toward the stop
day++adds one, so eventually the condition becomes false.
Trace the first, last, and forbidden loop values
Most loop bugs are boundary bugs. A loop has to agree on whether its index is zero-based or one-based and whether its ending value belongs in the range. The starter below prints four lines even though there are only three lessons: it starts at 0 and includes the endpoint 3. Run it, then repair it in either of these consistent ways: start at 1 and keep <= total_lessons, or start at 0 and use lesson < total_lessons.
Repair an off-by-one loop
This code runs, but its numbering and count do not match a three-lesson path. Change one part of the loop header, predict the output, then run it again.
Edit the program, predict its output, then run it.
Let the inner loop finish before the outer loop advances
A nested loop means one repetition happens inside another. In the program below, the outer loop chooses a week. For that one week, the inner loop runs through every day. Only after days 1 through 3 are printed does the outer loop advance to the next week. With weeks = 2 and days = 3, expect 2 * 3, or six lines of output.
Trace a two-level practice schedule
Run the program and notice that the day counter resets to 1 each time a new week begins. Change weeks or days and calculate the total lines before running it.
Edit the program, predict its output, then run it.
Nested loops are useful for grids, schedules, groups and items, or every pair of values. They are also easy to make hard to read. Give each index a meaningful name such as week and day, keep the body small, and calculate the total work before adding a large nested loop to a real program.
Use while when the changing state defines the stop
A while loop is best when the work should continue until some state changes: tasks remaining, bytes read, a menu choice, or a retry count. Its condition appears at the top, so it may run zero times. That is often the correct behavior when there is no work to do.
Make a while loop finish
remaining controls the loop and remaining-- changes that same value each cycle. Remove the update to see the runner explain the missing stopping progress.
Edit the program, predict its output, then run it.
Trace a while loop before you write it
For the example above, start with remaining = 3. The condition remaining > 0 is true, so the body prints 3 and then remaining-- changes the state to 2. The next two passes use 2 and 1. After the body prints 1, the update makes remaining zero; 0 > 0 is false, so the body does not run again and the completion message prints.
Zero-cycle case
The initial condition is already false, so the loop body runs zero times. The statement after the loop still runs.
One-cycle case
The body runs once, then the update changes the value to the stopping boundary.
Typical case
Each cycle has the same shape: test, print the current fact, decrement, and test again.
Failure case
The condition keeps reading the same positive value. The program has no reason to stop.
That repeated fact is called a loop invariant: at the start of every pass, remaining is the number of tasks that have not yet been reported. A good invariant helps you choose the right condition and makes a debugging trace much less mysterious.
Use do-while when one attempt must happen first
A do/while loop puts the condition after its body. That means its body runs at least once, even when the condition is false after that first pass. It is useful for a prompt that must appear once before a user can choose to stop, but use it only when that “at least once” rule is genuinely part of the problem.
Run a first check before testing again
The body prints once before checks < 2 is evaluated. Change checks to 2 before the loop and see why the program still prints the first check.
Edit the program, predict its output, then run it.
Use break and continue sparingly and trace their target
break leaves the nearest loop immediately. continue skips the rest of the current cycle; a for loop still performs its update before testing again, and a while loop returns directly to its condition. They are useful for an exceptional case inside otherwise regular repetition, but a plain loop condition is still the clearest normal stopping rule.
Skip one cycle and stop after a found result
Attempt 2 uses continue, so it never reaches the normal check. Attempt 4 uses break, so attempts 5 and later never start. Trace each outcome before running it.
Edit the program, predict its output, then run it.
Validate numeric input before relying on it
The previous lesson showed that scanf converts input only when the provided text matches the requested format. A production C program should also check its conversion count. The complete local pattern is if (scanf("%d", &completed) != 1) { /* recover or stop */ }. The browser lesson runner deliberately keeps function-call results out of conditions; it stops on invalid numeric input instead of imitating a full C runtime. You can still validate a successfully read value with range checks such as completed < 0 || completed > total.
- 01Read one value
Ask
scanfto convert input into the type your variable was declared to hold. - 02Check conversion locally
If the conversion count is not the expected value, do not treat the variable as trustworthy program state.
- 03Check the domain rule
For a completed lesson count, reject values below zero and values above the total.
- 04Only then repeat work
The later loop can rely on a value that has both the correct type and a meaningful range.
Debug one-character mistakes with a precise rule
This program looks like an equality check but uses an assignment operator in the condition. Run it first, read the runner message, and replace only the one character that changes the rule. Then change one of the values and observe the other branch.
Repair an equality condition
The runner makes the = versus == distinction explicit so you can connect a small syntactic difference to a different program behavior.
Edit the program, predict its output, then run it.
Debug control flow with evidence, not guesses
A condition or loop can be syntactically valid and still describe the wrong rule. When output surprises you, reduce the problem to one known state and trace it in order. Do not change several operators at once: that hides which change fixed the behavior.
- 01Write down the input state
Record the exact values before the decision: for example
completed = 3andtotal = 4. - 02Evaluate the condition aloud
Replace variable names with values and decide whether the question is true or false before looking at output.
- 03Mark the branch or one loop cycle
Name the exact body that should run, then record the update and the next condition result.
- 04Test the boundaries
Use the value below a limit, the exact limit, and the value above it. These tests expose most
<versus<=mistakes.
Compile local control flow with warnings enabled
Save a program as conditions.c and compile with warnings enabled. A compiler can catch many suspicious constructs, including a likely assignment in a condition, but it cannot decide whether your chosen boundary or stopping rule matches the program you meant to write. Trace at least one true and one false path by hand before trusting the terminal output.
clang -Wall -Wextra -Wpedantic -Wconversion conditions.c -o conditions./conditionsgcc -Wall -Wextra -Wpedantic -Wconversion conditions.c -o conditions./conditionsUse small boundary inputs: zero, the exact limit, one below it, and one above it.cl /W4 conditions.cconditions.exeConfirm that each path and loop stopping condition produces the result you can explain.Independent lab: print a learning-path status
Use the starter to read a completed-lesson count and print one line for every lesson. It already rejects an impossible value and marks each lesson as complete or next. Change the total, labels, or valid range to fit a learning path you care about. Then try the boundary inputs 0, the exact total, and one value outside the valid range.
Build a guarded learning-path report
This lab combines numeric input, a range check, a while loop, a nested if branch, and an explicit return status.
Edit the program, predict its output, then run it.
Make input safe
Keep the conversion and range decision before the loop. Test -1, 0, and a value greater than the total.
Trace both branches
Use an input of 2 and explain why two lines are complete while the remaining lines are next.
Change one rule
Add a clear status category—such as “review”—by changing the condition and its label, not by duplicating the loop.
Prove the boundary
With a total of 6, test 0 and 6. Explain the exact final loop value that makes the condition false.
Lesson review
Conditions turn data into a choice; loops repeat work while that choice allows another cycle. Clear control flow uses descriptive state, a visible comparison, ordered branches, braces around every branch, and a named update that moves a loop toward its stopping point. When input is involved, confirm both conversion and meaning before the program relies on it.
- I can read
==,!=,<,<=,>, and>=as precise comparisons instead of vague symbols. - I can explain the difference between assignment with
=and comparison with==, and I use braces around everyifandelsebody. - I can order an
if/else if/elsechain from the most specific boundary to the remaining alternative, knowing that only the first true branch runs. - I can choose
forfor a known count andwhilefor a state-driven stop, then trace initialization, condition, body, and update. - I can test a loop's first value, last allowed value, number of cycles, and the value immediately after the final update.
- I can explain why an inner loop completes all of its work before an outer loop advances, and estimate the total work in a nested loop.
- I can name the value that changes inside a loop and prove why the condition will eventually become false, including the zero-cycle case.
- I can distinguish a successful
scanfconversion check from a separate range check on the value that was read.