Exercise 2-10. Rewrite the function
lower, which converts upper case letters to lower case, with a conditional expression instead ofif-else.
This exercise looks trivial on the surface — it is a one-liner. The real lesson is about the conditional (ternary) operator and what it means to choose it over if-else. K&R introduce the ternary here precisely because lower is a function whose two branches each return a single value: the perfect shape for a conditional expression. Understanding why the arithmetic c + 'a' - 'A' works, and when ternary makes code clearer versus harder to read, is what the exercise is actually testing.
How the Arithmetic Works
In ASCII, uppercase letters occupy codes 65 (‘A’) through 90 (‘Z’). Lowercase letters occupy 97 (‘a’) through 122 (‘z’). The gap between any uppercase letter and its lowercase counterpart is always exactly 32 — 'a' - 'A' == 32. Both ranges are contiguous, so adding 32 to any uppercase letter lands on the correct lowercase letter. Writing c + 'a' - 'A' instead of c + 32 is deliberate: it avoids burying a magic number in the code and makes the intent self-documenting.
Solution
/* K&R Exercise 2-10 — lower() with the conditional operator
* Compile: gcc -ansi -Wall ex2-10.c -o ex2-10 */
#include <stdio.h>
int lower(int c);
int main(void)
{
printf("lower('A') = '%c'\n", lower('A')); /* a */
printf("lower('Z') = '%c'\n", lower('Z')); /* z */
printf("lower('m') = '%c'\n", lower('m')); /* m — unchanged */
printf("lower('5') = '%c'\n", lower('5')); /* 5 — unchanged */
return 0;
}
/* Return lowercase of c if c is uppercase; return c unchanged otherwise. */
int lower(int c)
{
return (c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c;
}
The parentheses around the condition (c >= 'A' && c <= 'Z') are not strictly required — the ternary operator has lower precedence than comparisons — but they improve readability by making the three parts of the expression visually distinct.
Compile and Run
gcc -ansi -Wall ex2-10.c -o ex2-10
./ex2-10
Sample Output
lower('A') = 'a'
lower('Z') = 'z'
lower('m') = 'm'
lower('5') = '5'
The Ternary Operator — Syntax and Usage
The conditional expression has the form:
condition ? value_if_true : value_if_false
It is an expression, not a statement — it produces a value, which is why it fits naturally inside a return. The original if-else version is equally correct; the ternary is not better in an absolute sense. It is better here because both branches are simple values and the whole thing reads as a single thought: “return the shifted character if uppercase, otherwise return it as-is.” When either branch involves side effects, multiple statements, or complex logic, if-else is clearer.
The Standard Library Alternative
For production code, prefer tolower() from <ctype.h>:
#include <ctype.h>
int ch = tolower('A'); /* 'a' */
tolower() handles locale-specific characters that ASCII arithmetic does not. The manual lower in this exercise exists to teach the underlying mechanics; in real code, reach for the standard function.
What This Exercise Teaches
- Conditional (ternary) operator — syntax, precedence, and when it improves readability over
if-else - ASCII arithmetic — why
c + 'a' - 'A'converts case and why both letter ranges being contiguous makes it work - Avoiding magic numbers — writing
'a' - 'A'instead of32for clarity and portability - Standard library awareness — knowing that
tolower()in<ctype.h>is the right tool for production use
Set Up Your C Environment
To compile and run this solution you need GCC installed. If you have not set up C on your machine yet:
- Install GCC on Windows 11
- Install GCC on macOS
- Install GCC on Ubuntu/Linux
- VS Code for C Programming — recommended editor
← Exercise 2-9 |
Chapter 2 Solutions |
Chapter 3 Solutions →
Book:
The C Programming Language, 2nd Ed — Kernighan & Ritchie