liveBook · Manning

Stopping criterion

As explained in Modern C

A controlling expression is an expression whose value determines the path taken by a conditional or other control-flow construct.

A loop that stops at five

`for (size_t i = 0; i < 5; ++i) { printf("%zu\n", i); }` prints 0 through 4. The loop condition `i < 5` is checked before each execution of the body. When it is false, the loop stops; `++i` changes the value tested on the next check. section 2.4.1

A stopping criterion is a condition used to decide when repeated work ends. In C, the expression making that decision is a controlling expression. Its value determines a control path: numerical zero is false, and any nonzero value is true. Read the surrounding construct carefully—a true `for` condition continues iteration, whereas a true `if` condition executes its dependent statement once. section 3.0 section 3.1 section 2.4.1

 8   size_t gcd2(size_t a, size_t b) {
 9     assert(a <= b);
10     if (!a) return b;
11     size_t rem = b % a;
12     return gcd2(rem, a);
13   }


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":1},{\"line\":0,\"ch\":2}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":11}],[{\"line\":3,\"ch\":7},{\"line\":3,\"ch\":13}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":11}],[{\"line\":3,\"ch\":7},{\"line\":3,\"ch\":13}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":11}],[{\"line\":3,\"ch\":7},{\"line\":3,\"ch\":13}],[{\"line\":1,\"ch\":1},{\"line\":1,\"ch\":2}],[{\"line\":1,\"ch\":7},{\"line\":1,\"ch\":13}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":2}],[{\"line\":2,\"ch\":7},{\"line\":2,\"ch\":9}],[{\"line\":2,\"ch\":15},{\"line\":2,\"ch\":21}],[{\"line\":4,\"ch\":7},{\"line\":4,\"ch\":13}],[{\"line\":3,\"ch\":0},{\"line\":3,\"ch\":2}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":11}],[{\"line\":3,\"ch\":7},{\"line\":3,\"ch\":13}],[{\"line\":4,\"ch\":0},{\"line\":4,\"ch\":2}],[{\"line\":2,\"ch\":15},{\"line\":2,\"ch\":21}],[{\"line\":4,\"ch\":7},{\"line\":4,\"ch\":13}],[{\"line\":5,\"ch\":0},{\"line\":5,\"ch\":2}]]"}
!@%STYLE%@!

In `gcd2`, `if (!a) return b;` checks for termination before the recursive call. Otherwise, the function computes a remainder and calls itself again. The precondition check with `assert` serves a different purpose: it checks whether the arguments are valid, not whether recursion should stop. section 7.3

TAKEAWAY: Check a recursive function’s termination condition first. Without that check, repeated calls can exhaust system resources. In the `for` example, the changing counter eventually makes the continuation condition false; in `gcd2`, reaching zero makes the return branch run instead of another recursive call. section 7.3 section 2.4.1

A wait loop adds another distinction. A `cnd_t` condition variable identifies what a thread waits for; it is not the condition expression that decides whether waiting should continue. Because a wait can return without that expression changing, check the expression again in a loop. A `finished` test can also let that loop end when the task is over. section 18.5

How Modern C covers it

How deep it goes
Works through loop and recursive checks, then distinguishes a thread’s condition expression from its condition variable.
Examples
Uses a five-iteration for loop, recursive greatest-common-divisor calculation, and a thread that rechecks whether work remains.
What it assumes
Introduces controlling expressions and numerical truth values while building on elementary C variables, comparisons, and statements.
What you can do after
Diagnose/debug with it: distinguish a missing recursive termination check from a valid loop condition, and recheck conditions after thread waits.
How it connects
Connects controlling expressions with for loops, if statements, recursion, preconditions, and condition variables.

Also explained in

Compare how 11 books explain stopping criterion →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.