K&R C Exercise 1-20: detab — Replace Tabs with Spaces

Exercise 1-20. Write a program detab that 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 % TABSTOP gives the number of columns you are past the last tab stop.
  • Subtracting from TABSTOP gives 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 col variable is a classic example of that pattern.
  • Modular arithmetic for alignment: col % TABSTOP computes position within the current tab interval — a general technique for any grid-aligned output.
  • Symbolic constants vs. variables: #define TABSTOP 8 is 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 col on 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:

← Exercise 1-19  | 
Chapter 1 Solutions  | 
Exercise 1-21 →

Book:

The C Programming Language, 2nd Ed — Kernighan & Ritchie

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>