A Decision Inside an Expression

Chapter 3 introduced cond ? a : b as the operator that selects one of two values. Week 3 is four programs the lab insists you write with it, and the insistence has a point: ?: is an expression, not a statement, so the decision can sit inside a printf argument or on the right of an assignment where an if cannot go. Three of the four are the same decisions chapter 5 will make with if and else; writing them as expressions first shows exactly what the statement form adds later, and what it does not. The fourth swaps a division for a single bit test, using the & operator from chapter 3.

Program 1: Positive or Negative

Read an integer and report whether it is positive or negative. Zero is neither, and a program that calls it one of them is wrong, so the decision has three outcomes and the operator has to nest.

Algorithm:

  1. Start.
  2. Read the integer n.
  3. If n > 0 the word is positive; otherwise if n < 0 the word is negative; otherwise the word is zero.
  4. Print n and the word.
  5. Stop.

Try 5, -3, and 0. The whole decision is one argument to printf: the operator evaluates n > 0, and only the chosen arm is evaluated, so for a positive number the inner test never runs. The inner ?: is in parentheses. The grammar does not require them, since ?: groups right to left and the nesting would parse correctly without, but nobody reading the line should have to know that, and the marks are for a line that reads correctly at a glance.

Program 2: Leap Year

A year is a leap year if it is divisible by 4, except that century years are leap years only when divisible by 400. 2024 and 2000 are leap years; 1900 and 2023 are not.

Algorithm:

  1. Start.
  2. Read the year.
  3. The year is a leap year if it is divisible by 4 and not by 100, or if it is divisible by 400.
  4. Print the year followed by whether it is a leap year.
  5. Stop.

The rule lives in leap, an int holding 1 or 0 exactly as chapter 3 described relational results, and the operator only chooses the wording. Splitting it this way keeps the printf line short and makes the rule testable on its own. The parentheses around the && part are again for the reader: && binds tighter than ||, so the line means the same without them, but the rule has a natural "this, unless that" shape and the brackets show it. Feed it 1900: divisible by 4 and by 100, not by 400, so the answer is not a leap year, the case every marking scheme includes.

Program 3: The Largest of Three Numbers

Algorithm:

  1. Start.
  2. Read a, b, and c.
  3. If a > b, the largest is a unless c is bigger, in which case c; otherwise the largest is b unless c is bigger, in which case c.
  4. Print the largest.
  5. Stop.

Read the assignment as a decision tree: the outer test picks the winner of a against b, and each arm then plays that winner against c. Two comparisons happen per run, never three, because the losing branch is never evaluated. Try 3 7 5, 9 2 4, 1 2 8, and then 5 5 5: with all three equal, a > b is false, b > c is false, and the answer is c, which is the same 5. Ties never break the program; they only decide which of several equal names gets printed. The two-step version, largest = (a > b) ? a : b; followed by largest = (largest > c) ? largest : c;, is equally correct and easier to extend to four numbers.

Program 4: Odd or Even with a Single Bit

The usual test is n % 2. The lab asks for the bitwise version: an integer is odd exactly when its lowest bit is 1, and n & 1 isolates that bit.

Algorithm:

  1. Start.
  2. Read the integer n.
  3. Compute n AND 1; if the result is 1 the number is odd, otherwise even.
  4. Print n and the word.
  5. Stop.

Chapter 3 showed & keeping only the bits set in both operands, and 1 has only the lowest bit set, so n & 1 is 1 for 7 (binary 111) and 0 for 10 (binary 1010). The parentheses around n & 1 are not optional in spirit: & does bind tighter than ?:, but & binds looser than ==, and the moment someone extends the line to n & 1 == 1 it silently becomes n & (1 == 1), which is n & 1 by luck and n & 0 for any other constant. Bracket the bit test and that whole family of bugs cannot start.

Try -7. It prints odd, which is right, because this machine stores negative numbers in two's complement and the lowest bit of -7 is 1. C89 does not require two's complement; it leaves the representation of negative values implementation-defined, so on paper the % version is the portable one and the & version is the fast one. In a viva, saying that sentence is worth more than either program.

Key Takeaways

  • cond ? a : b is an expression: it can be a printf argument or the right-hand side of an assignment, and only the chosen arm is evaluated.
  • Three outcomes need a nested ?:; put the inner one in parentheses so the line reads correctly without knowing the grouping rule.
  • Leap year: divisible by 4 and not by 100, or divisible by 400. Store the rule in an int and let the operator choose the wording.
  • The largest of three is a two-level decision tree; ties are harmless because equal values print the same.
  • n & 1 is the lowest bit, 1 for odd; always bracket it, because & binds looser than ==.
  • n & 1 for negative n depends on two's complement, which C89 does not guarantee; n % 2 is the portable test.