Exercise 1-20. Write a program
detabthat replaces tabs in the input with the proper number of blanks to space to the next tab stop. Assume a fixed set of tab stops, say every n columns. Should n be a variable or a symbolic parameter?
Approach
The key insight is that a tab does not always expand to the same number of spaces — it expands to however many spaces it takes to reach the next tab stop. At column 0 a tab inserts 8 spaces; at column 5 it inserts only 3; at column 8 it inserts another full 8. To compute this correctly, the program must track the current column position at every character it processes. The formula TABSTOP - (col % TABSTOP) gives exactly the number of spaces needed to advance from the current column to the next stop.
On the variable-vs-symbolic-parameter question: n should be a #define constant, not a runtime variable. Tab stops are a fixed property of the display environment (terminals have used 8-column tab stops by convention for decades). Making it a #define communicates that it is a compile-time constant, lets the compiler fold it into every arithmetic expression at zero runtime cost, and allows any programmer to change it in one place for their environment.
Solution
/* detab: replace tabs with spaces to the next tab stop */
/* Compile: gcc -ansi -Wall detab.c -o detab */
#include <stdio.h>
#define TABSTOP 8
int main(void)
{
int c, col;
col = 0;
while ((c = getchar()) != EOF) {
if (c == '\t') {
int spaces = TABSTOP - (col % TABSTOP);
while (spaces-- > 0) {
putchar(' ');
++col;
}
} else if (c == '\n') {
putchar(c);
col = 0; /* newline resets column counter */
} else {
putchar(c);
++col;
}
}
return 0;
}
Understanding the Tab-Stop Formula
The expression TABSTOP - (col % TABSTOP) is the heart of the program. Here is how it works step by step:
col % TABSTOPgives the number of columns you are past the last tab stop.- Subtracting from
TABSTOPgives the number of spaces needed to reach the next tab stop.
Concrete examples with TABSTOP = 8:
Current column (col) |
col % 8 |
Spaces emitted | Column after tab |
|---|---|---|---|
| 0 | 0 | 8 − 0 = 8 | 8 |
| 5 | 5 | 8 − 5 = 3 | 8 |
| 7 | 7 | 8 − 7 = 1 | 8 |
| 8 | 0 | 8 − 0 = 8 | 16 |
| 13 | 5 | 8 − 5 = 3 | 16 |
Notice that every tab always advances the column to the next multiple of 8, regardless of where it starts — which is exactly what a terminal does.
Compile and Run
gcc -ansi -Wall detab.c -o detab
./detab
The program reads from standard input, so you can pipe text directly to it:
printf 'hello\tworld\n' | ./detab
echo -e 'col0\tcol8\tcol16' | ./detab
You can also redirect a file:
./detab < source.c
Sample Output
Input (tabs shown as →, spaces as ·):
hello→world a→b→c →indented
Output (with TABSTOP = 8):
hello···world (5 chars + 3 spaces to reach col 8) a·······b·······c (1 + 7 spaces to col 8, then 1 + 7 to col 16) ········indented (8 spaces: tab from col 0 to col 8)
What This Exercise Teaches
- Column-tracking state: many text-processing programs need to carry state (here, the current column position) across characters in a single pass. The
colvariable is a classic example of that pattern. - Modular arithmetic for alignment:
col % TABSTOPcomputes position within the current tab interval — a general technique for any grid-aligned output. - Symbolic constants vs. variables:
#define TABSTOP 8is the idiomatic C answer when a value is a fixed environmental assumption, not something the user should vary per run. It costs nothing at runtime and makes intent clear. - Handling multiple character cases: the three-way branch (tab / newline / other) is the standard K&R pattern for character-level filters. Resetting
colon newline is the easy-to-miss correctness detail.
Set Up Your C Environment
To compile and run this solution you need GCC. If you haven’t 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
- Complete C Development Environment Setup
← Exercise 1-19 |
Chapter 1 Solutions |
Exercise 1-21 →
Book:
The C Programming Language, 2nd Ed — Kernighan & Ritchie