Chapter roadmap
Decompose programs into reusable functions with clear contracts, parameters, return values, references, overloads, and controlled scope. Work through the concepts in order, type every example yourself, and keep a short debugging log that records predictions, errors, fixes, and what each fix taught you.
Learning objectives
- Declare and define functions
- Pass values and references
- Return meaningful results
- Use overloads and scope responsibly
04.1
Function contracts
A function should perform one named task. Its signature states the return type, name, and parameter types. A declaration lets the compiler know the signature before use; the definition contains the body. Preconditions describe valid input and postconditions describe the promised result.
Before running the example, trace each expression and write down the expected state or result. Then run it, compare the actual result, and change one input or rule to confirm that you understand which part controls the behavior.
Exampledouble rectangleArea(double width, double height);
int main() {
std::cout << rectangleArea(4.0, 2.5);
}
double rectangleArea(double width, double height) {
return width * height;
}Result10
Check your understandingExplain the example in plain language, identify one boundary or failure case, and revise it so the output changes in a predictable way.
04.2
Value and reference parameters
Pass-by-value gives the function a copy, so changes remain local. A reference parameter aliases the caller's variable and can intentionally modify it. const references avoid copying large objects while promising not to change them.
Before running the example, trace each expression and write down the expected state or result. Then run it, compare the actual result, and change one input or rule to confirm that you understand which part controls the behavior.
Examplevoid swapValues(int& left, int& right) {
int temporary = left;
left = right;
right = temporary;
}
int a = 3, b = 9;
swapValues(a, b);Resulta = 9, b = 3
Check your understandingExplain the example in plain language, identify one boundary or failure case, and revise it so the output changes in a predictable way.
04.3
Return values and early returns
A non-void function must return a value on every reachable path. A return can end a function early when an invalid case or completed result is found. Prefer returning a result over changing global state because returned data is easier to test and reuse.
Before running the example, trace each expression and write down the expected state or result. Then run it, compare the actual result, and change one input or rule to confirm that you understand which part controls the behavior.
Examplebool isPrime(int number) {
if (number < 2) return false;
for (int divisor = 2; divisor * divisor <= number; ++divisor) {
if (number % divisor == 0) return false;
}
return true;
}ResultisPrime(29) -> true
isPrime(30) -> false
Check your understandingExplain the example in plain language, identify one boundary or failure case, and revise it so the output changes in a predictable way.
04.4
Overloading and scope
Overloaded functions share a name but have different parameter lists. The compiler selects a matching version at compile time. Local variables exist only inside their block; global variables should be rare because hidden shared state makes behavior difficult to predict.
Before running the example, trace each expression and write down the expected state or result. Then run it, compare the actual result, and change one input or rule to confirm that you understand which part controls the behavior.
Exampleint larger(int a, int b) { return a > b ? a : b; }
double larger(double a, double b) { return a > b ? a : b; }
std::cout << larger(4, 9) << " " << larger(3.2, 1.8);Result9 3.2
Check your understandingExplain the example in plain language, identify one boundary or failure case, and revise it so the output changes in a predictable way.
Chapter assignments
Complete these in order. Later assignments assume that earlier skills are working. Do not only test the sample values; design tests that challenge boundaries, missing values, incorrect types, empty collections, and other likely failures.
- A4.1
Write conversion functions for miles/kilometers and Fahrenheit/Celsius, then build a menu that calls them.
Submit readable source code, a brief design note, and evidence from at least three tests including one boundary or invalid case.
- A4.2
Create reusable functions for minimum, maximum, sum, and average of three numbers without duplicating calculations.
Submit readable source code, a brief design note, and evidence from at least three tests including one boundary or invalid case.
- A4.3
Build a password checker returning separate results for length, uppercase, lowercase, digit, and symbol rules.
Submit readable source code, a brief design note, and evidence from at least three tests including one boundary or invalid case.
- A4.4
Refactor a previous loop project so input, validation, calculation, and reporting are separate functions.
Submit readable source code, a brief design note, and evidence from at least three tests including one boundary or invalid case.
Chapter project
Modular Statistics Console
Modular Statistics Console โ Read a collection of scores and call separate functions to validate input, calculate mean, median, range, and letter distribution, then format a report. Document every function's contract and test functions independently.
Required process
- Write a short specification listing inputs, outputs, rules, and failure cases.
- Break the work into small functions, queries, modules, or classes appropriate to the language.
- Build the smallest working version before adding optional features.
- Test normal, boundary, empty, and invalid cases and record the results.
- Refactor names and duplication, then write a concise user guide.
Key terms
- signature
- declaration
- definition
- parameter
- argument
- reference
- return type
- scope
- overload