Selection, Iteration, and Program FlowIntroductionA program is not merely a list of instructions executed from top to bottom. Useful software must make decisions, repeat operations, respond to changing data, and terminate safely. These capabilities are provided by program-flow statements. In C++, Java, and Python, the principal flow-control mechanisms are Boolean expressions, conditional selection, pattern or switch selection, iteration, nesting, scope control, and transfer statements. This chapter develops these mechanisms from first principles and applies them to structured programming problems. Although the three languages use different syntax, their underlying logic is similar. A condition evaluates to either true or false; a selection statement chooses among alternatives; and a loop repeats a block while a controlling condition permits it. Learning ObjectivesBy the end of this chapter, you should be able to: - construct and evaluate Boolean expressions;
- use
if, else if, and else correctly; - apply
switch in C++ and Java and match in Python where appropriate; - design
while, do-while, and for loops; - use nested selection and iteration safely;
- explain block scope and variable lifetime;
- apply
break, continue, and controlled early return; - identify infinite loops, off-by-one errors, and unreachable code;
- select an appropriate flow-control structure for a practical problem;
- test programs containing alternative paths and repeated execution.
1. Boolean Logic: The Foundation of DecisionsA Boolean expression is an expression whose result is true or false. In C++, Java, and Python, relational operators compare values: | Operator | Meaning |
|---|
== | equal to | != | not equal to | < | less than | > | greater than | <= | less than or equal to | >= | greater than or equal to |
Logical operators combine Boolean expressions. C++ and Java use && for AND, || for OR, and ! for NOT. Python uses and, or, and not. For two propositions P and Q, conjunction is true only when both are true, while disjunction is true when at least one is true. Negation reverses a proposition's truth value. | P | Q | P AND Q | P OR Q |
|---|
| false | false | false | false | | false | true | false | true | | true | false | false | true | | true | true | true | true |
Short-circuit evaluationIn an AND expression, evaluation can stop as soon as a false operand is found. In an OR expression, evaluation can stop as soon as a true operand is found. This is called short-circuit evaluation. It can improve efficiency and prevent errors: if denominator != 0 and numerator / denominator > 2:
print("Condition satisfied")The division is attempted only if denominator != 0 is true. Without short-circuit protection, the program could attempt division by zero. Precedence and clarityOperators are evaluated according to precedence rules. Parentheses should be used when they improve clarity or prevent misunderstanding: if ((age >= 18 && hasId) || isStaff) {
allowEntry();
}A common error is confusing assignment with comparison. In C++, = assigns a value, whereas == compares values. Java also distinguishes these operators. Python uses = for assignment and == for comparison. 2. Conditional SelectionThe if statementAn if statement executes a block only when its condition is true. if (temperature > 30) {
cout << "Hot day";
}Equivalent Java code is: if (temperature > 30) {
System.out.println("Hot day");
}Python uses indentation rather than braces: if temperature > 30:
print("Hot day")The body of a conditional should be clearly delimited. In C++ and Java, braces are recommended even for a one-statement body because they reduce errors when statements are later added. Two-way selectionAn if-else statement selects exactly one of two alternatives. if mark >= 50:
result = "Pass"
else:
result = "Fail"The condition is evaluated once. If it is true, the first block executes; otherwise, the second block executes. Multi-way selectionAn if-else if-else chain is appropriate when conditions represent ranges or complex tests. if (mark >= 80) {
grade = 'A';
} else if (mark >= 70) {
grade = 'B';
} else if (mark >= 60) {
grade = 'C';
} else if (mark >= 50) {
grade = 'D';
} else {
grade = 'F';
}The order matters. Once a true condition is found, later conditions are skipped. Conditions should normally be arranged from the most restrictive or highest range to the lowest. If mark >= 50 appeared first, every passing mark would incorrectly receive the same result. Guard clausesA guard clause handles an invalid or exceptional condition immediately and returns from a function. This reduces nesting: def calculate_average(total, count):
if count <= 0:
return None
return total / countGuard clauses are useful for input validation, but they should not conceal important cleanup or bypass required security checks. 3. Pattern and Switch SelectionWhen a program selects an action based on one discrete value, a switch-style structure can be clearer than a long conditional chain. C++ and Java switchswitch (choice) {
case 1:
cout << "Create";
break;
case 2:
cout << "Search";
break;
case 3:
cout << "Exit";
break;
default:
cout << "Invalid choice";
}The break statement prevents execution from continuing into the next case. Omitting it may cause fall-through, which is sometimes deliberate but is often a defect. default handles values that match no listed case. Modern Java also provides switch expressions, and modern C++ provides enhanced forms of selection, but compatibility depends on the compiler and language version. Code intended for teaching or deployment should state its required version. Python matchPython 3.10 introduced structural pattern matching: match command:
case "start":
begin_service()
case "stop":
stop_service()
case _:
print("Unknown command")The underscore is a wildcard pattern. Python's match can match structures, not merely constants, and therefore differs conceptually from a simple C-style switch. Choosing between conditional and switch-style selectionUse if when conditions involve ranges, unrelated Boolean expressions, or complex relationships. Use switch or simple match when one expression is compared with several discrete alternatives. The objective is readability and correct coverage, not merely shorter code. 4. Iteration and Loop DesignA loop repeats a block of statements. Every reliable loop has three conceptual components: - Initialization establishes the starting state.
- Continuation condition determines whether another iteration is allowed.
- Progress or update moves the program toward termination.
If progress does not eventually make the condition false, the loop may be infinite. while loop
A while loop is a pre-test loop: its condition is checked before each iteration. It may execute zero times. int count = 1;
while (count <= 5) {
cout << count << " ";
count++;
}The output is 1 2 3 4 5. The variable count is initialized before the loop and updated inside it. Python syntax is similar: count = 1
while count <= 5:
print(count)
count += 1do-while loop
C++ and Java provide do-while, a post-test loop. Its body executes at least once. do {
choice = readChoice();
} while (choice < 1 || choice > 3);This is appropriate for menu input when the user must be prompted at least once. Python has no built-in do-while statement; the same behavior can be created using while True and a controlled break. while True:
choice = int(input("Choice: "))
if 1 <= choice <= 3:
breakfor loop
A for loop is useful when iteration is controlled by a counter or a collection. for (int i = 0; i < 5; i++) {
System.out.println(i);
}This prints values from 0 through 4. The upper bound is exclusive because the continuation condition is i < 5. Python's for loop iterates over items: for i in range(5):
print(i)range(5) produces 0, 1, 2, 3, and 4. With range(start, stop, step), the stop value remains exclusive.
Sentinel-controlled iterationA sentinel is a special value that signals completion and is not treated as ordinary data. total = 0
while True:
value = int(input("Enter value, -1 to finish: "))
if value == -1:
break
total += valueThe sentinel must be chosen so that it cannot be confused with valid data, or the input design must explicitly document that limitation. Counting and accumulationA counter records how many times an event occurs; an accumulator combines values. passed = 0
sum_marks = 0
for mark in marks:
sum_marks += mark
if mark >= 50:
passed += 1If marks contains n values, the average is calculated as: average = summarks ÷ n Here, sum_marks is the total of all marks and n is the number of marks. The formula is applicable only when n > 0; otherwise division by zero must be prevented. 5. Nested Control StructuresA control structure placed inside another is nested. For example, a nested loop can process rows and columns of a table: for row in range(3):
for column in range(4):
print(row, column)The inner loop completes all four iterations for each outer-loop iteration, producing 3 × 4 = 12 pairs. Nested structures are useful for matrices, grids, timetables, and search problems, but deep nesting can reduce readability and increase the possibility of errors. A nested conditional might validate a user before checking a requested operation: if (authenticated) {
if (hasPermission) {
performOperation();
} else {
deny("Insufficient permission");
}
} else {
deny("Authentication required");
}Security-sensitive conditions should be explicit. A program must not treat authentication and authorization as interchangeable concepts. 6. Scope and LifetimeScope is the region of source code in which a name can be accessed. A variable declared inside a block normally has block scope. int value = 10;
if (value > 0) {
int messageCode = 1;
cout << messageCode;
}
// messageCode is unavailable hereJava follows similar block-scope rules. Python has function and module scope, but an if block does not create a separate local scope in the same way. Nevertheless, excessive reuse of names can make Python programs difficult to understand. A variable should be declared in the narrowest scope that meets its purpose. This reduces accidental modification and makes dependencies easier to identify. Shadowing—declaring an inner variable with the same name as an outer variable—can be legal but confusing and should generally be avoided. Lifetime describes how long a variable exists. A local variable commonly exists during execution of its function or block, while an object managed by a language runtime may remain alive while references to it exist. Scope and lifetime are related but not identical. 7. Flow-Control Transferbreak
break exits the nearest loop or switch. It is useful when the answer has been found or a sentinel is encountered.
for item in items:
if item == target:
found = True
breakcontinue
continue skips the remainder of the current iteration and begins the next iteration.
for number in range(1, 11):
if number % 2 == 0:
continue
print(number)This prints odd numbers. Excessive use of continue can make the control path harder to follow, so a positively structured condition may sometimes be clearer. return
return ends a function and optionally supplies a value. It is often the cleanest way to report a result or reject invalid input. Functions should have predictable return behavior; mixing unrelated return types without documentation makes calling code fragile.
ExceptionsExceptions are appropriate for abnormal events that cannot be handled conveniently through ordinary conditions, such as a failed file operation or invalid conversion. They should not replace ordinary validation in every case. A program should catch only exceptions it can meaningfully handle and should not silently discard error information. 8. Common Errors and Testing StrategiesOff-by-one errorsAn off-by-one error occurs when a loop executes one time too many or too few. Carefully distinguish < from <=, and document whether a bound is inclusive or exclusive. Accidental infinite loopsTypical causes include a missing update, an update in the wrong direction, or a condition that can never become false. A loop invariant—the property expected to remain true during iteration—helps reason about correctness. Dangling elseIn nested C++ or Java conditionals without braces, an else attaches to the nearest unmatched if. Braces eliminate this ambiguity. Unreachable or incomplete branchesEvery relevant input category should be covered. A default branch, validation condition, or explicit error response can prevent silent failure. Testing flow controlTests should include: - the smallest valid input;
- the largest valid input;
- values at each boundary;
- invalid input;
- empty collections;
- one-item collections;
- repeated values;
- conditions that cause zero loop iterations;
- conditions that cause exactly one iteration;
- conditions that exercise every branch.
Code coverage can show which branches were executed, but coverage alone does not prove correctness. Assertions and expected-output tests are also required. 9. Worked Example: A Menu-Based Grade ProcessorSuppose a training centre needs a program that repeatedly accepts marks, counts passes and failures, and displays a report when the user chooses to finish. A mark is valid only when it lies from 0 through 100 inclusive. passed = 0
failed = 0
total = 0
count = 0
while True:
print("1. Enter mark")
print("2. Display report")
print("3. Exit")
choice = input("Choice: ")
if choice == "1":
mark = int(input("Mark: "))
if mark < 0 or mark > 100:
print("Invalid mark")
continue
total += mark
count += 1
if mark >= 50:
passed += 1
else:
failed += 1
elif choice == "2":
if count == 0:
print("No marks entered")
else:
average = total / count
print("Average:", average)
print("Passed:", passed)
print("Failed:", failed)
elif choice == "3":
break
else:
print("Unknown choice")AnalysisThe outer while True creates a menu that continues until break. The first selection validates the mark. The continue statement prevents invalid data from reaching the accumulation logic. The second selection uses a guard condition to prevent division by zero. The third selection terminates the loop. The final branch handles unexpected menu input. The average formula is valid only when count > 0. The program maintains the invariant that count equals the number of valid marks represented by total, passed, and failed. This invariant helps detect programming errors during testing. 10. Applied Case: Library Self-Service KioskBackgroundA library wants a kiosk through which a member can search for a book, borrow it, or return it. The system must reject unauthenticated users and prevent borrowing when the member has reached the loan limit. ProblemThe kiosk must repeatedly display operations, validate input, and handle different book and member states. A poorly designed program might allow an unauthorized user to reach borrowing code or might continue processing after an invalid identifier. Analysis and approachA suitable design uses: - a guard clause for authentication;
- a loop for repeated menu interaction;
- switch-style selection for fixed commands;
- nested conditions for availability and loan limits;
- explicit termination through an exit command.
Illustrative pseudocode is: if authentication fails:
display error
stop
repeat:
display menu
read command
if command is SEARCH:
read title
display matching books
else if command is BORROW:
read book identifier
if book does not exist:
display error
else if book is unavailable:
display error
else if member has reached loan limit:
display error
else:
create loan record
else if command is RETURN:
process return
else if command is EXIT:
stop
else:
display invalid commandOutcome and learning pointsThe design separates authentication, command selection, validation, and business action. This makes the code easier to test and reduces the chance that a failed validation will fall through to an operation. In a real system, authorization decisions must be enforced on the server or protected application layer, not only in a kiosk interface. Audit logs should record borrowing and return actions, while personal data should be protected according to applicable privacy requirements. 11. Professional Practice and Contemporary ConsiderationsReadable control flow is a professional quality attribute. Use meaningful names, consistent indentation, small functions, and comments that explain intent rather than restating syntax. Prefer structured alternatives to deeply nested or unrestricted jumps. Static analysis tools can identify unreachable branches, suspicious conditions, missing break statements, and some possible infinite loops. AI-assisted programming tools can suggest loops and conditions, but generated code must be reviewed. Common AI-generated defects include incorrect boundary conditions, assumptions about input formats, and missing authorization checks. Developers remain responsible for testing, security, licensing compliance, and correctness. Flow-control choices also have ethical consequences. A validation branch that rejects users unfairly, mishandles accessibility requirements, or silently loses data is not merely a technical defect. Programs should provide clear feedback, preserve user control, and fail safely. In safety-critical or financially significant systems, requirements should specify exceptional behavior and independent testing should verify it. Chapter SummaryProgram flow determines how software responds to data and events. Boolean expressions provide the true-or-false decisions required by selection and iteration. if structures are suitable for ranges and complex conditions, while switch or match is effective for discrete alternatives. while, do-while, and for loops support different repetition patterns, and every loop requires initialization, a continuation condition, and progress toward termination. Nested structures solve multidimensional and staged problems but should be controlled for readability. Scope limits where names can be used, while lifetime describes how long values exist. break, continue, return, and exceptions provide controlled transfer, but they should be applied deliberately. Professional programs validate boundaries, prevent infinite loops, test every branch, protect authorization decisions, and use clear, maintainable structure. Key TermsBoolean expression: An expression whose result is true or false. Condition: A Boolean test that controls program execution. Selection: Choosing one execution path from alternatives. Iteration: Repeated execution of a block of statements. Short-circuit evaluation: Stopping Boolean evaluation when the result is already known. Guard clause: An early condition that handles invalid or exceptional input. Switch: A multi-way selection structure based on discrete values. Pattern matching: Selection based on the form or value of data. Loop: A control structure that repeats statements. Pre-test loop: A loop whose condition is checked before its body executes. Post-test loop: A loop whose body executes before its condition is checked. Sentinel: A special value that signals the end of input. Counter: A variable used to record occurrences or iterations. Accumulator: A variable that progressively combines values. Nesting: Placing one control structure inside another. Scope: The region in which a name can be accessed. Lifetime: The period during which a variable or object exists. Fall-through: Continuing from one switch case into another without a terminating statement. Loop invariant: A property that remains true during loop execution. Off-by-one error: A boundary error causing one extra or one missing iteration. Review QuestionsShort Answer Questions- What is a Boolean expression, and why is it important in program flow?
- Distinguish between a pre-test loop and a post-test loop.
- What is the purpose of
break in a switch statement? - Explain the difference between scope and lifetime.
- Why must a program guard against division by zero when calculating an average?
Long Answer Questions- Compare
if-else, switch, and Python match selection. State when each is most appropriate. - Explain the three components of a reliable loop and illustrate each with code.
- Discuss common causes of infinite loops and off-by-one errors, including testing methods.
- Explain nesting, guard clauses, and scope in the design of a menu-driven program.
- Describe how authorization, validation, and error handling should be implemented in a self-service application.
Analytical / Application Questions- Design a program that reads positive integers until a sentinel is entered and reports the count, total, and average. Identify the condition needed to avoid division by zero.
- A loop is intended to print integers from 1 through 10 but prints only 1 through 9. Diagnose the likely condition error and propose a correction.
- Design the control flow for an examination system that accepts marks, rejects invalid values, assigns grades, and reports the average. Identify at least five boundary tests.
Multiple Choice Questions with AnswersQuestion 1Which operator represents logical AND in Java? A. || B. && C. ! D. == Correct Answer: B. && Question 2Which loop is guaranteed to execute its body at least once in C++? A. while B. for C. do-while D. range Correct Answer: C. do-while Question 3What is the purpose of a sentinel value? A. To increase loop speed B. To signal the end of input C. To declare a variable D. To select a class Correct Answer: B. To signal the end of input Question 4What prevents division by zero when calculating an average? A. Checking that the count is greater than zero B. Using a switch statement C. Using continue after division D. Declaring the total as a string Correct Answer: A. Checking that the count is greater than zero Question 5What commonly happens in a C++ switch when break is omitted? A. The program always terminates B. The next case may execute C. The condition becomes false D. The switch becomes a loop Correct Answer: B. The next case may execute Question 6What does continue do inside a loop? A. Exits every enclosing function B. Repeats the current statement indefinitely C. Skips to the next iteration D. Terminates the program Correct Answer: C. Skips to the next iteration Question 7How many pairs are produced by a loop with 3 outer iterations and 4 complete inner iterations? A. 7 B. 12 C. 16 D. 24 Correct Answer: B. 12 Question 8Which structure is generally most suitable for checking whether a mark lies within several ranges? A. if-else-if chain B. switch with no cases C. break statement D. try statement only Correct Answer: A. if-else-if chain Question 9What is an off-by-one error? A. A syntax error in a variable name B. A loop boundary error causing one extra or missing iteration C. A failure to import a library D. A memory allocation method Correct Answer: B. A loop boundary error causing one extra or missing iteration Question 10Why should variables usually be declared in the narrowest practical scope? A. To increase accidental modification B. To make dependencies and access easier to control C. To guarantee infinite loops D. To eliminate all Boolean expressions Correct Answer: B. To make dependencies and access easier to control
|